Template
Organize Vertex starter into reusable sections
Use remote logos and avatars, refine landing copy, and document the template structure.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import Image from "next/image"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export function VertexMark({ className }: { className?: string }) {
|
||||
return (
|
||||
<Image
|
||||
src="/logo.svg"
|
||||
alt=""
|
||||
width={24}
|
||||
height={24}
|
||||
className={cn("brightness-0 dark:invert", className)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function Brand({ compact = false }: { compact?: boolean }) {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-2.5">
|
||||
<VertexMark className="size-8" />
|
||||
{!compact && (
|
||||
<span className="text-[17px] font-semibold tracking-[-0.03em]">Vertex</span>
|
||||
)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export function FeatureCopy({
|
||||
title,
|
||||
description,
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
}) {
|
||||
return (
|
||||
<div className="relative z-10 bg-background p-6 sm:p-7">
|
||||
<h3 className="text-lg font-medium tracking-[-0.025em]">{title}</h3>
|
||||
<p className="mt-2 max-w-md text-sm leading-6 text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export function FrameCrosses() {
|
||||
return (
|
||||
<>
|
||||
<span className="frame-cross left-0 top-0" aria-hidden="true" />
|
||||
<span className="frame-cross right-0 top-0" aria-hidden="true" />
|
||||
<span className="frame-cross bottom-0 left-0" aria-hidden="true" />
|
||||
<span className="frame-cross bottom-0 right-0" aria-hidden="true" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import Image from "next/image"
|
||||
|
||||
export interface Testimonial {
|
||||
avatar: string
|
||||
name: string
|
||||
role: string
|
||||
quote: string
|
||||
}
|
||||
|
||||
export function ReviewCard({ review }: { review: Testimonial }) {
|
||||
return (
|
||||
<figure className="h-full w-[310px] shrink-0 rounded-xl border bg-card/75 p-5 shadow-sm transition-colors hover:bg-muted/40 sm:w-[360px]">
|
||||
<blockquote className="text-sm leading-6 text-foreground/85">“{review.quote}”</blockquote>
|
||||
<figcaption className="mt-6 flex items-center gap-3">
|
||||
<Image
|
||||
src={review.avatar}
|
||||
alt=""
|
||||
width={36}
|
||||
height={36}
|
||||
sizes="36px"
|
||||
unoptimized
|
||||
className="size-9 shrink-0 rounded-full border object-cover"
|
||||
/>
|
||||
<span>
|
||||
<span className="block text-sm font-medium">{review.name}</span>
|
||||
<span className="block text-xs text-muted-foreground">{review.role}</span>
|
||||
</span>
|
||||
</figcaption>
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export function SectionHeading({
|
||||
eyebrow,
|
||||
title,
|
||||
description,
|
||||
className,
|
||||
}: {
|
||||
eyebrow: string
|
||||
title: string
|
||||
description: string
|
||||
className?: string
|
||||
}) {
|
||||
return (
|
||||
<div className={cn("border-b px-6 py-16 text-center sm:px-10 sm:py-20", className)}>
|
||||
<div className="mx-auto max-w-2xl">
|
||||
<p className="mb-4 font-mono text-[11px] font-medium uppercase tracking-[0.18em] text-blue-600 dark:text-blue-400">
|
||||
{eyebrow}
|
||||
</p>
|
||||
<h2 className="text-balance text-3xl font-medium tracking-[-0.045em] sm:text-4xl md:text-[44px] md:leading-[1.05]">
|
||||
{title}
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-xl text-pretty text-sm leading-6 text-muted-foreground sm:text-base">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user