tenext redesign
This commit is contained in:
52
components/sections/about/AboutCTA.tsx
Normal file
52
components/sections/about/AboutCTA.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { tenextButton as TenextButton } from "@/components/shared/Button";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { aboutCta } from "@/data/about";
|
||||
|
||||
/** AboutCTA — large enterprise call to action on a premium gradient panel. */
|
||||
export function AboutCTA() {
|
||||
return (
|
||||
<section className="px-5 py-[60px] md:py-[80px]">
|
||||
<div className="relative overflow-hidden rounded-[25px] bg-tenext-dark px-[7vw] py-[80px] text-center md:py-[100px]">
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<div className="absolute left-1/2 top-[-40%] h-[600px] w-[600px] -translate-x-1/2 rounded-full bg-[radial-gradient(circle,rgba(103,102,200,0.35),transparent_60%)]" />
|
||||
<div className="absolute bottom-[-50%] left-[15%] h-[420px] w-[420px] rounded-full bg-[radial-gradient(circle,rgba(69,208,189,0.16),transparent_60%)]" />
|
||||
</div>
|
||||
|
||||
<PageContainer className="relative z-10 flex flex-col items-center">
|
||||
<h2
|
||||
className="max-w-[760px] tracking-[-0.03em] text-white"
|
||||
style={{
|
||||
fontFamily: "var(--font-dm-sans)",
|
||||
fontSize: "clamp(30px, 4vw, 56px)",
|
||||
fontWeight: 600,
|
||||
lineHeight: 1.1,
|
||||
}}
|
||||
>
|
||||
{aboutCta.title}
|
||||
</h2>
|
||||
<p className="mt-[22px] max-w-[560px] text-[17px] leading-[1.75] text-white/80">
|
||||
{aboutCta.paragraph}
|
||||
</p>
|
||||
<div className="mt-[40px] flex flex-wrap items-center justify-center gap-[16px]">
|
||||
<TenextButton
|
||||
href={aboutCta.primaryCta.href}
|
||||
variant="gradient-fill"
|
||||
className="rounded-[25px] px-[36px] py-[16px] text-[15px] font-semibold"
|
||||
showArrow={false}
|
||||
>
|
||||
{aboutCta.primaryCta.label}
|
||||
</TenextButton>
|
||||
<TenextButton
|
||||
href={aboutCta.secondaryCta.href}
|
||||
variant="gradient-border"
|
||||
className="rounded-[25px] px-[36px] py-[16px] text-[15px] font-medium text-white"
|
||||
showArrow={true}
|
||||
>
|
||||
{aboutCta.secondaryCta.label}
|
||||
</TenextButton>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
96
components/sections/about/AboutHero.tsx
Normal file
96
components/sections/about/AboutHero.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import Link from "next/link";
|
||||
import { tenextButton as TenextButton } from "@/components/shared/Button";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { aboutHero } from "@/data/about";
|
||||
|
||||
const floatIcons = ["cloud", "cpu", "database", "code", "shield", "boxes"];
|
||||
|
||||
/**
|
||||
* AboutHero — flagship enterprise hero.
|
||||
* Left: breadcrumb, headline, supporting paragraph, primary + secondary CTA.
|
||||
* Right: an asset-free glass-tile composition of capability icons (no photos).
|
||||
*/
|
||||
export function AboutHero() {
|
||||
return (
|
||||
<section className="px-5 pt-5">
|
||||
<div className="relative overflow-hidden rounded-[25px] bg-tenext-dark px-[7vw] py-[80px] md:py-[110px]">
|
||||
{/* Ambient gradient wash */}
|
||||
<div className="pointer-events-none absolute inset-0 opacity-70">
|
||||
<div className="absolute -right-[10%] -top-[30%] h-[600px] w-[600px] rounded-full bg-[radial-gradient(circle,rgba(130,88,200,0.35),transparent_60%)]" />
|
||||
<div className="absolute -bottom-[40%] left-[10%] h-[500px] w-[500px] rounded-full bg-[radial-gradient(circle,rgba(69,208,189,0.18),transparent_60%)]" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 grid grid-cols-1 items-center gap-[50px] lg:grid-cols-[1.1fr_0.9fr]">
|
||||
{/* Content */}
|
||||
<div>
|
||||
<nav aria-label="Breadcrumb" className="mb-[26px]">
|
||||
<ol className="flex items-center gap-2 text-[13px] text-white/60">
|
||||
<li>
|
||||
<Link href="/" className="transition-colors hover:text-tenext-teal">
|
||||
Home
|
||||
</Link>
|
||||
</li>
|
||||
<li className="h-1 w-1 rounded-full bg-tenext-teal" />
|
||||
<li className="text-white">About us</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<span className="tenext-subheading mb-[18px] text-tenext-teal" style={{ fontFamily: "var(--font-sora)" }}>
|
||||
{aboutHero.eyebrow}
|
||||
</span>
|
||||
|
||||
<h1
|
||||
className="max-w-[640px] tracking-[-0.03em] text-white"
|
||||
style={{
|
||||
fontFamily: "var(--font-dm-sans)",
|
||||
fontSize: "clamp(38px, 5vw, 72px)",
|
||||
fontWeight: 600,
|
||||
lineHeight: 1.06,
|
||||
}}
|
||||
>
|
||||
{aboutHero.title}
|
||||
</h1>
|
||||
|
||||
<p className="mt-[26px] max-w-[540px] text-[17px] leading-[1.75] text-white/80">
|
||||
{aboutHero.paragraph}
|
||||
</p>
|
||||
|
||||
<div className="mt-[40px] flex flex-wrap items-center gap-[16px]">
|
||||
<TenextButton
|
||||
href={aboutHero.primaryCta.href}
|
||||
variant="gradient-fill"
|
||||
className="rounded-[25px] px-[34px] py-[15px] text-[15px] font-semibold"
|
||||
showArrow={false}
|
||||
>
|
||||
{aboutHero.primaryCta.label}
|
||||
</TenextButton>
|
||||
<TenextButton
|
||||
href={aboutHero.secondaryCta.href}
|
||||
variant="gradient-border"
|
||||
className="rounded-[25px] px-[34px] py-[15px] text-[15px] font-medium text-white"
|
||||
showArrow={true}
|
||||
>
|
||||
{aboutHero.secondaryCta.label}
|
||||
</TenextButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Icon composition */}
|
||||
<div className="relative hidden lg:block" aria-hidden="true">
|
||||
<div className="grid grid-cols-3 gap-[16px]">
|
||||
{floatIcons.map((name, i) => (
|
||||
<div
|
||||
key={name}
|
||||
className="flex aspect-square items-center justify-center rounded-[22px] border border-white/10 bg-white/[0.04] text-tenext-teal backdrop-blur-sm transition-transform duration-500 hover:-translate-y-1"
|
||||
style={{ transform: `translateY(${i % 2 === 0 ? "-12px" : "12px"})` }}
|
||||
>
|
||||
<Icon name={name} className="h-[34px] w-[34px]" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
57
components/sections/about/AboutIndustries.tsx
Normal file
57
components/sections/about/AboutIndustries.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import Link from "next/link";
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { ArrowIcon } from "@/components/shared/icons/ArrowIcon";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { industries } from "@/data/site-pages";
|
||||
import { industryIcons } from "@/data/about";
|
||||
|
||||
/** AboutIndustries — premium industry cards (replaces the plain text list). */
|
||||
export function AboutIndustries() {
|
||||
return (
|
||||
<SectionContainer paddingY="lg" className="bg-white px-[20px]">
|
||||
<PageContainer>
|
||||
<SectionHeading
|
||||
tag="industries"
|
||||
title="Depth across the industries you operate in"
|
||||
description="We bring domain understanding and engineering rigor to the sectors where Tenext delivers transformation."
|
||||
titleClassName="text-tenext-dark max-w-[720px]"
|
||||
descriptionClassName="max-w-[620px]"
|
||||
className="mb-[50px]"
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 gap-[20px] sm:grid-cols-2 lg:grid-cols-3">
|
||||
{industries.map((industry, index) => (
|
||||
<RevealOnView key={industry.id} delay={index * 80}>
|
||||
<Link
|
||||
href={`/industries#${industry.id}`}
|
||||
className="group relative flex h-full flex-col justify-between overflow-hidden rounded-[25px] border border-tenext-card-border bg-tenext-dark p-[35px] transition-all duration-300 hover:-translate-y-2 hover:shadow-[0_22px_55px_rgba(31,31,31,0.22)]"
|
||||
>
|
||||
<div className="pointer-events-none absolute -right-[20%] -top-[30%] h-[240px] w-[240px] rounded-full bg-[radial-gradient(circle,rgba(69,208,189,0.16),transparent_65%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
|
||||
|
||||
<span className="relative flex h-[60px] w-[60px] items-center justify-center rounded-[16px] bg-white/[0.06] text-tenext-teal">
|
||||
<Icon name={industryIcons[industry.id] ?? "building"} className="h-[28px] w-[28px]" />
|
||||
</span>
|
||||
|
||||
<div className="relative mt-[70px]">
|
||||
<h3 className="font-[var(--font-dm-sans)] text-[22px] font-bold text-white">
|
||||
{industry.title}
|
||||
</h3>
|
||||
<p className="mt-[12px] text-[15px] leading-[1.7] text-tenext-text-muted">
|
||||
{industry.description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<span className="relative mt-[24px] flex h-[42px] w-[42px] items-center justify-center rounded-full border border-white/15 text-white transition-colors duration-300 group-hover:bg-tenext-teal group-hover:text-tenext-dark">
|
||||
<ArrowIcon className="h-[14px] w-[14px]" />
|
||||
</span>
|
||||
</Link>
|
||||
</RevealOnView>
|
||||
))}
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
66
components/sections/about/AboutPracticeTeams.tsx
Normal file
66
components/sections/about/AboutPracticeTeams.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { tenextButton as TenextButton } from "@/components/shared/Button";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { practiceTeamCards } from "@/data/about";
|
||||
|
||||
/**
|
||||
* AboutPracticeTeams — the disciplines that staff an engagement.
|
||||
* Each card has a unique gradient header and icon (no repeated artwork,
|
||||
* no invented individuals).
|
||||
*/
|
||||
export function AboutPracticeTeams() {
|
||||
return (
|
||||
<SectionContainer paddingY="lg" className="bg-white px-[20px]">
|
||||
<PageContainer>
|
||||
<div className="mb-[50px] flex flex-col gap-[24px] md:flex-row md:items-end md:justify-between">
|
||||
<SectionHeading
|
||||
tag="practice teams"
|
||||
title="Specialist teams behind every engagement"
|
||||
description="Engagements are staffed from practices that work together — so the people who design a system are the ones who build and support it."
|
||||
titleClassName="text-tenext-dark max-w-[640px]"
|
||||
descriptionClassName="max-w-[560px]"
|
||||
/>
|
||||
<TenextButton
|
||||
href="/careers"
|
||||
variant="simple"
|
||||
className="shrink-0 text-[15px] font-semibold text-tenext-dark"
|
||||
showArrow={true}
|
||||
>
|
||||
See open roles
|
||||
</TenextButton>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-[20px] sm:grid-cols-2 lg:grid-cols-3">
|
||||
{practiceTeamCards.map((team, index) => (
|
||||
<RevealOnView key={team.name} delay={index * 80}>
|
||||
<div className="group flex h-full flex-col overflow-hidden rounded-[25px] border border-tenext-card-border transition-all duration-300 hover:-translate-y-2 hover:shadow-[0_22px_55px_rgba(31,31,31,0.12)]">
|
||||
{/* Unique gradient header */}
|
||||
<div className={`relative h-[130px] bg-gradient-to-br ${team.gradient}`}>
|
||||
<div className="absolute inset-0 opacity-30 [background-image:radial-gradient(rgba(255,255,255,0.5)_1px,transparent_1px)] [background-size:16px_16px]" />
|
||||
<span className="absolute bottom-[-26px] left-[30px] flex h-[54px] w-[54px] items-center justify-center rounded-[16px] border border-white/20 bg-tenext-dark text-tenext-teal transition-transform duration-500 group-hover:-translate-y-1">
|
||||
<Icon name={team.icon} className="h-[26px] w-[26px]" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-1 flex-col p-[30px] pt-[40px]">
|
||||
<h3 className="font-[var(--font-dm-sans)] text-[20px] font-bold text-tenext-dark">
|
||||
{team.name}
|
||||
</h3>
|
||||
<p className="mt-[4px] text-[14px] font-semibold text-tenext-teal">
|
||||
/ {team.focus} /
|
||||
</p>
|
||||
<p className="mt-[14px] text-[15px] leading-[1.7] text-tenext-text-muted">
|
||||
{team.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</RevealOnView>
|
||||
))}
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
48
components/sections/about/DeliveryModel.tsx
Normal file
48
components/sections/about/DeliveryModel.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { deliverySteps } from "@/data/about";
|
||||
|
||||
/** DeliveryModel — connected timeline: Discover → … → Support. */
|
||||
export function DeliveryModel() {
|
||||
return (
|
||||
<SectionContainer paddingY="lg" className="bg-tenext-dark px-[20px]">
|
||||
<PageContainer>
|
||||
<SectionHeading
|
||||
tag="delivery model"
|
||||
title="A transparent path from idea to lasting impact"
|
||||
description="Every engagement moves through the same disciplined flow, so progress and cost stay visible at each step."
|
||||
titleClassName="text-white max-w-[720px]"
|
||||
descriptionClassName="max-w-[620px] text-tenext-text-muted"
|
||||
className="mb-[60px]"
|
||||
/>
|
||||
|
||||
<div className="relative grid grid-cols-1 gap-[20px] sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
|
||||
{/* Connecting line (desktop) */}
|
||||
<div className="pointer-events-none absolute left-0 right-0 top-[36px] hidden h-px bg-gradient-to-r from-tenext-teal/10 via-tenext-teal/40 to-tenext-teal/10 xl:block" />
|
||||
|
||||
{deliverySteps.map((step, index) => (
|
||||
<RevealOnView key={step.title} delay={index * 90} className="relative">
|
||||
<div className="flex flex-col items-start gap-[16px]">
|
||||
<div className="relative z-10 flex h-[72px] w-[72px] items-center justify-center rounded-[20px] border border-white/10 bg-tenext-dark text-tenext-teal">
|
||||
<Icon name={step.icon} className="h-[30px] w-[30px]" />
|
||||
<span className="absolute -right-2 -top-2 flex h-[26px] w-[26px] items-center justify-center rounded-full bg-tenext-teal text-[12px] font-bold text-tenext-dark">
|
||||
{index + 1}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-[var(--font-sora)] text-[18px] font-bold text-white">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-[14px] leading-[1.65] text-tenext-text-muted">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</RevealOnView>
|
||||
))}
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
85
components/sections/about/IconCardGrid.tsx
Normal file
85
components/sections/about/IconCardGrid.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { IconCard } from "@/data/about";
|
||||
|
||||
interface IconCardGridProps {
|
||||
id?: string;
|
||||
eyebrow?: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
items: IconCard[];
|
||||
columns?: 2 | 3 | 4;
|
||||
theme?: "light" | "surface" | "dark";
|
||||
}
|
||||
|
||||
const colClass: Record<number, string> = {
|
||||
2: "sm:grid-cols-2",
|
||||
3: "sm:grid-cols-2 lg:grid-cols-3",
|
||||
4: "sm:grid-cols-2 lg:grid-cols-4",
|
||||
};
|
||||
|
||||
/**
|
||||
* IconCardGrid — reusable premium icon-card section for the About page.
|
||||
* Powers Mission/Vision/Values, Why Tenext, Capabilities, Technology
|
||||
* Ecosystem, and Enterprise Trust with a single, consistent card.
|
||||
*/
|
||||
export function IconCardGrid({
|
||||
id,
|
||||
eyebrow,
|
||||
title,
|
||||
description,
|
||||
items,
|
||||
columns = 3,
|
||||
theme = "light",
|
||||
}: IconCardGridProps) {
|
||||
const isDark = theme === "dark";
|
||||
const sectionBg =
|
||||
theme === "dark"
|
||||
? "bg-tenext-dark"
|
||||
: theme === "surface"
|
||||
? "bg-tenext-surface-muted"
|
||||
: "bg-white";
|
||||
|
||||
const cardBase = isDark
|
||||
? "border-white/10 bg-white/[0.03] hover:border-tenext-teal/40"
|
||||
: "border-tenext-card-border bg-white hover:border-tenext-teal/50";
|
||||
const titleColor = isDark ? "text-white" : "text-tenext-dark";
|
||||
|
||||
return (
|
||||
<SectionContainer id={id} paddingY="lg" className={`${sectionBg} px-[20px] scroll-mt-[110px]`}>
|
||||
<PageContainer>
|
||||
<SectionHeading
|
||||
tag={eyebrow}
|
||||
title={title}
|
||||
description={description}
|
||||
titleClassName={`${titleColor} max-w-[760px]`}
|
||||
descriptionClassName={`max-w-[640px] ${isDark ? "text-tenext-text-muted" : ""}`}
|
||||
className="mb-[50px]"
|
||||
/>
|
||||
|
||||
<div className={`grid grid-cols-1 gap-[20px] ${colClass[columns]}`}>
|
||||
{items.map((item, index) => (
|
||||
<RevealOnView key={item.title} delay={index * 80}>
|
||||
<div
|
||||
className={`group flex h-full flex-col gap-[16px] rounded-[25px] border p-[35px] transition-all duration-300 hover:-translate-y-2 hover:shadow-[0_22px_55px_rgba(31,31,31,0.12)] ${cardBase}`}
|
||||
>
|
||||
<span className="flex h-[54px] w-[54px] items-center justify-center rounded-[15px] bg-tenext-teal/10 text-tenext-teal transition-colors duration-300 group-hover:bg-tenext-teal group-hover:text-tenext-dark">
|
||||
<Icon name={item.icon} className="h-[26px] w-[26px]" />
|
||||
</span>
|
||||
<h3 className={`font-[var(--font-sora)] text-[20px] font-bold leading-[1.3] ${titleColor}`}>
|
||||
{item.title}
|
||||
</h3>
|
||||
<p className="text-[15px] leading-[1.7] text-tenext-text-muted">
|
||||
{item.description}
|
||||
</p>
|
||||
</div>
|
||||
</RevealOnView>
|
||||
))}
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
60
components/sections/about/OurStory.tsx
Normal file
60
components/sections/about/OurStory.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { ourStory } from "@/data/about";
|
||||
|
||||
const focusAreas = [
|
||||
{ icon: "code", label: "Engineering" },
|
||||
{ icon: "cloud", label: "Cloud" },
|
||||
{ icon: "cpu", label: "AI" },
|
||||
{ icon: "database", label: "Data" },
|
||||
{ icon: "workflow", label: "Digital Transformation" },
|
||||
{ icon: "chart", label: "Business Outcomes" },
|
||||
];
|
||||
|
||||
/** OurStory — company narrative with a focus-area rail. */
|
||||
export function OurStory() {
|
||||
return (
|
||||
<SectionContainer paddingY="lg" className="bg-tenext-surface-muted px-[20px]">
|
||||
<PageContainer>
|
||||
<div className="grid grid-cols-1 gap-[50px] lg:grid-cols-[0.85fr_1.15fr] lg:gap-[80px]">
|
||||
<RevealOnView>
|
||||
<SectionHeading
|
||||
tag={ourStory.eyebrow}
|
||||
title={ourStory.title}
|
||||
titleClassName="text-tenext-dark"
|
||||
/>
|
||||
<div className="mt-[36px] grid grid-cols-2 gap-[14px]">
|
||||
{focusAreas.map((area) => (
|
||||
<div
|
||||
key={area.label}
|
||||
className="flex items-center gap-[12px] rounded-[15px] border border-tenext-card-border bg-white px-[18px] py-[14px]"
|
||||
>
|
||||
<span className="text-tenext-teal">
|
||||
<Icon name={area.icon} className="h-[20px] w-[20px]" />
|
||||
</span>
|
||||
<span className="text-[14px] font-semibold text-tenext-dark font-[var(--font-sora)]">
|
||||
{area.label}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</RevealOnView>
|
||||
|
||||
<RevealOnView delay={120} className="flex flex-col gap-[24px]">
|
||||
{ourStory.paragraphs.map((paragraph, i) => (
|
||||
<p
|
||||
key={i}
|
||||
className={`leading-[1.85] text-tenext-text-muted ${i === 0 ? "text-[19px] text-tenext-dark" : "text-[16px]"}`}
|
||||
>
|
||||
{paragraph}
|
||||
</p>
|
||||
))}
|
||||
</RevealOnView>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
69
components/sections/about/TeamSection.tsx
Normal file
69
components/sections/about/TeamSection.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
"use client";
|
||||
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { SectionHeading } from "@/components/shared/SectionHeading";
|
||||
import { tenextButton as TenextButton } from "@/components/shared/Button";
|
||||
import { practiceTeams } from "@/data/site-content";
|
||||
|
||||
export function TeamSection() {
|
||||
return (
|
||||
<SectionContainer id="teams" paddingY="lg" className="scroll-mt-[120px]">
|
||||
<PageContainer>
|
||||
<div className="columns-1 gap-6 sm:columns-2 lg:columns-4">
|
||||
<div className="mb-6 flex break-inside-avoid flex-col">
|
||||
<SectionHeading
|
||||
tag="our teams"
|
||||
title="Specialist teams behind every engagement"
|
||||
titleClassName="text-tenext-dark"
|
||||
/>
|
||||
<p className="mt-[24px] text-[16px] leading-[1.8] text-tenext-text-muted">
|
||||
Engagements are staffed from practices that work together —
|
||||
engineering, cloud, data, mobility, and commerce — so the people
|
||||
who design a system are the ones who build and support it.
|
||||
</p>
|
||||
<TenextButton
|
||||
href="/careers"
|
||||
variant="simple"
|
||||
className="mt-[25px] text-[15px] font-medium text-tenext-dark"
|
||||
showArrow={true}
|
||||
>
|
||||
See open roles
|
||||
</TenextButton>
|
||||
</div>
|
||||
|
||||
{practiceTeams.map((team, i) => (
|
||||
<div
|
||||
key={`${team.name}-${i}`}
|
||||
className="group relative mb-6 break-inside-avoid overflow-hidden rounded-[25px] bg-tenext-card-dark"
|
||||
>
|
||||
<div className="relative aspect-[3/4] w-full">
|
||||
<img
|
||||
src={team.image}
|
||||
alt=""
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src =
|
||||
"/images/tenext/home-9-img.png";
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-80" />
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 w-full p-6 text-white transition-transform duration-300 group-hover:-translate-y-2">
|
||||
<h4
|
||||
className="text-[20px] font-bold"
|
||||
style={{ fontFamily: "var(--font-dm-sans)" }}
|
||||
>
|
||||
{team.name}
|
||||
</h4>
|
||||
<p className="text-[14px] text-tenext-teal">/ {team.focus} /</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
58
components/sections/about/WhoWeAre.tsx
Normal file
58
components/sections/about/WhoWeAre.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { SectionContainer } from "@/components/shared/SectionContainer";
|
||||
import { PageContainer } from "@/components/shared/PageContainer";
|
||||
import { RevealOnView } from "@/components/shared/RevealOnView";
|
||||
import { Icon } from "@/components/shared/Icon";
|
||||
import { whoWeAre } from "@/data/about";
|
||||
|
||||
/** WhoWeAre — balanced two-column: positioning statement + what/who/why. */
|
||||
export function WhoWeAre() {
|
||||
return (
|
||||
<SectionContainer paddingY="lg" className="bg-white px-[20px]">
|
||||
<PageContainer>
|
||||
<div className="grid grid-cols-1 gap-[50px] lg:grid-cols-2 lg:gap-[80px]">
|
||||
{/* Left */}
|
||||
<RevealOnView>
|
||||
<span className="tenext-subheading mb-[16px] text-tenext-teal" style={{ fontFamily: "var(--font-sora)" }}>
|
||||
{whoWeAre.eyebrow}
|
||||
</span>
|
||||
<h2
|
||||
className="max-w-[480px] tracking-[-0.03em] text-tenext-dark"
|
||||
style={{
|
||||
fontFamily: "var(--font-dm-sans)",
|
||||
fontSize: "clamp(30px, 3.6vw, 48px)",
|
||||
fontWeight: 500,
|
||||
lineHeight: 1.12,
|
||||
}}
|
||||
>
|
||||
{whoWeAre.title}
|
||||
</h2>
|
||||
<p className="mt-[24px] max-w-[460px] text-[17px] leading-[1.75] text-tenext-text-muted">
|
||||
{whoWeAre.lead}
|
||||
</p>
|
||||
</RevealOnView>
|
||||
|
||||
{/* Right */}
|
||||
<div className="flex flex-col gap-[24px]">
|
||||
{whoWeAre.points.map((point, index) => (
|
||||
<RevealOnView key={point.title} delay={index * 90}>
|
||||
<div className="flex gap-[22px] rounded-[25px] border border-tenext-card-border p-[30px] transition-transform duration-300 hover:-translate-y-1">
|
||||
<span className="flex h-[54px] w-[54px] shrink-0 items-center justify-center rounded-[15px] bg-tenext-teal/10 text-tenext-teal">
|
||||
<Icon name={point.icon} className="h-[26px] w-[26px]" />
|
||||
</span>
|
||||
<div>
|
||||
<h3 className="mb-[8px] font-[var(--font-sora)] text-[19px] font-bold text-tenext-dark">
|
||||
{point.title}
|
||||
</h3>
|
||||
<p className="text-[15px] leading-[1.7] text-tenext-text-muted">
|
||||
{point.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</RevealOnView>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</SectionContainer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user