mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 20:05:06 +03:00
wip
This commit is contained in:
1 parent
035928fb2a
commit
70b0d66ccf
3 files changed
+151
-141
No files matched your search
@@ -118,80 +118,80 @@ export function BuiltWithSupabaseSection() {
|
||||
|
||||
<div className="mx-auto max-w-[var(--container-max-w,75rem)] px-6 w-full">
|
||||
{/* Featured row - 2 large cells */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{featuredExamples.map((example) => {
|
||||
const logo = EXAMPLE_LOGO[example.title]
|
||||
const Skeleton = SKELETON_CONTENT[example.title]
|
||||
return (
|
||||
<Link
|
||||
key={example.title}
|
||||
href={example.repo_url ?? '#'}
|
||||
target="_blank"
|
||||
className="group flex flex-col bg-surface-75 border border-border rounded-lg overflow-hidden hover:bg-surface-100 transition-colors"
|
||||
>
|
||||
<div className="px-6 py-5 flex flex-col gap-2.5">
|
||||
{logo && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt=""
|
||||
className={`h-5 w-fit object-contain ${logo.invert ? ' dark:invert' : ''}`}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<h4 className="text-foreground text-sm font-medium">{example.title}</h4>
|
||||
<p className="text-foreground-lighter text-sm mt-1 line-clamp-2">
|
||||
{example.description}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{featuredExamples.map((example) => {
|
||||
const logo = EXAMPLE_LOGO[example.title]
|
||||
const Skeleton = SKELETON_CONTENT[example.title]
|
||||
return (
|
||||
<Link
|
||||
key={example.title}
|
||||
href={example.repo_url ?? '#'}
|
||||
target="_blank"
|
||||
className="group flex flex-col bg-surface-75 border border-border rounded-lg overflow-hidden hover:bg-surface-100 transition-colors"
|
||||
>
|
||||
<div className="px-6 py-5 flex flex-col gap-2.5">
|
||||
{logo && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt=""
|
||||
className={`h-5 w-fit object-contain ${logo.invert ? ' dark:invert' : ''}`}
|
||||
/>
|
||||
)}
|
||||
<div>
|
||||
<h4 className="text-foreground text-sm font-medium">{example.title}</h4>
|
||||
<p className="text-foreground-lighter text-sm mt-1 line-clamp-2">
|
||||
{example.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 flex items-center justify-center px-6 pt-4 pb-0 overflow-hidden">
|
||||
{/* Browser frame */}
|
||||
<div className="w-full rounded-t-lg border border-b-0 border-border-stronger/50 shadow-lg -mb-[10%] overflow-hidden">
|
||||
{/* Title bar */}
|
||||
<div className="flex items-center gap-1.5 px-3 py-2.5 border-b border-border bg-background-200">
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
</div>
|
||||
{/* Skeleton content */}
|
||||
<div className="h-[240px] flex items-center justify-center bg-background">
|
||||
{Skeleton ? <Skeleton /> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 flex items-center justify-center px-6 pt-4 pb-0 overflow-hidden">
|
||||
{/* Browser frame */}
|
||||
<div className="w-full rounded-t-lg border border-b-0 border-border-stronger/50 shadow-lg -mb-[10%]">
|
||||
{/* Title bar */}
|
||||
<div className="flex items-center gap-1.5 px-3 py-2.5 border-b border-border">
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
<span className="size-2.5 rounded-full bg-foreground-muted/30" />
|
||||
</div>
|
||||
{/* Skeleton content */}
|
||||
<div className="h-[240px] flex items-center justify-center bg-foreground/[0.03]">
|
||||
{Skeleton ? <Skeleton /> : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Grid row - 4 smaller cells */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mt-3">
|
||||
{gridExamples.map((example) => {
|
||||
const logo = EXAMPLE_LOGO[example.title]
|
||||
return (
|
||||
<Link
|
||||
key={example.title}
|
||||
href={example.repo_url ?? '#'}
|
||||
target="_blank"
|
||||
className="group flex flex-col bg-surface-75 border border-border rounded-lg px-6 py-10 hover:bg-surface-100 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
{logo && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt=""
|
||||
className={`h-5 w-5 object-contain${logo.invert ? ' dark:invert' : ''}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<h4 className="text-foreground text-sm font-medium">{example.title}</h4>
|
||||
<p className="text-foreground-lighter text-sm mt-1 line-clamp-2">
|
||||
{example.description}
|
||||
</p>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mt-3">
|
||||
{gridExamples.map((example) => {
|
||||
const logo = EXAMPLE_LOGO[example.title]
|
||||
return (
|
||||
<Link
|
||||
key={example.title}
|
||||
href={example.repo_url ?? '#'}
|
||||
target="_blank"
|
||||
className="group flex flex-col bg-surface-75 border border-border rounded-lg px-6 py-10 hover:bg-surface-100 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
{logo && (
|
||||
<img
|
||||
src={logo.src}
|
||||
alt=""
|
||||
className={`h-5 w-5 object-contain${logo.invert ? ' dark:invert' : ''}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<h4 className="text-foreground text-sm font-medium">{example.title}</h4>
|
||||
<p className="text-foreground-lighter text-sm mt-1 line-clamp-2">
|
||||
{example.description}
|
||||
</p>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -6,21 +6,6 @@ import { useState } from 'react'
|
||||
import { Button, cn } from 'ui'
|
||||
|
||||
const customerStories = [
|
||||
{
|
||||
name: 'Resend',
|
||||
logo: '/images/customers/logos/resend.png',
|
||||
icon: '/images/customers/logos/resend-icon.svg',
|
||||
tagline: 'Scaling seamlessly to 5,000+ paying customers and millions of emails sent daily.',
|
||||
quote:
|
||||
"The Supabase YC Program made it a no-brainer for us. We didn't have to worry about backend costs in the early days, which gave us more runway to focus on product-market fit.",
|
||||
author: 'Zeno Rocha, CEO, Resend',
|
||||
authorImg: '/images/blog/avatars/zeno-rocha.png',
|
||||
slug: 'resend',
|
||||
bgColor: '#000000',
|
||||
bgGradient: 'linear-gradient(to bottom left, #0a0a0a 0%, #000000 100%)',
|
||||
dimBgColor: '#080808',
|
||||
textColor: 'light' as 'light' | 'dark',
|
||||
},
|
||||
{
|
||||
name: 'Firecrawl',
|
||||
logo: '/images/customers/logos/firecrawl.png',
|
||||
@@ -32,9 +17,28 @@ const customerStories = [
|
||||
authorImg: '/images/blog/avatars/caleb-peffer.jpg',
|
||||
slug: 'firecrawl',
|
||||
rawIcon: true,
|
||||
bgColor: '#7a3818',
|
||||
bgGradient: 'linear-gradient(to bottom left, #7a3818 0%, #4a1e08 100%)',
|
||||
dimBgColor: '#5a2a10',
|
||||
iconFilter: 'brightness(0) invert(1)',
|
||||
bgColor: 'color(display-p3 0.980392 0.364706 0.098039)',
|
||||
bgGradient:
|
||||
'linear-gradient(to bottom left, color(display-p3 0.980392 0.364706 0.098039 / 1) 0%, color(display-p3 0.980392 0.364706 0.098039 / 0.9) 100%)',
|
||||
dimBgColor: 'color(display-p3 0.980392 0.364706 0.098039 / 0.9)',
|
||||
textColor: 'light' as 'light' | 'dark',
|
||||
},
|
||||
{
|
||||
name: 'Rally',
|
||||
logo: '/images/customers/logos/rally.png',
|
||||
icon: '/images/customers/logos/rally-icon.svg',
|
||||
rawIcon: true,
|
||||
tagline: 'From first line of code to fully licensed fintech in three months.',
|
||||
quote:
|
||||
"We could not have built this company without Supabase. If I had to go and build all these components myself, we wouldn't even have launched.",
|
||||
author: 'Thiago Peres, Founder & CTO, Rally',
|
||||
authorImg: 'https://avatars.githubusercontent.com/u/914007?v=4',
|
||||
slug: 'rally',
|
||||
bgColor: 'color(display-p3 0.275 0.306 0.8)',
|
||||
bgGradient:
|
||||
'linear-gradient(to bottom left, color(display-p3 0.275 0.306 0.8 / 1) 0%, color(display-p3 0.118 0.176 0.769 / 1) 100%)',
|
||||
dimBgColor: 'color(display-p3 0.118 0.176 0.769 / 1)',
|
||||
textColor: 'light' as 'light' | 'dark',
|
||||
},
|
||||
{
|
||||
@@ -63,9 +67,11 @@ const customerStories = [
|
||||
authorImg: '/images/blog/avatars/vasek-mlejnsky.jpg',
|
||||
slug: 'e2b',
|
||||
rawIcon: true,
|
||||
bgColor: '#7a4400',
|
||||
bgGradient: 'linear-gradient(to bottom left, #7a4400 0%, #4a2800 100%)',
|
||||
dimBgColor: '#5a3200',
|
||||
iconFilter: 'brightness(0) invert(1)',
|
||||
bgColor: 'color(display-p3 1 0.533 0)',
|
||||
bgGradient:
|
||||
'linear-gradient(to bottom left, color(display-p3 1 0.533 0 / 1) 0%, color(display-p3 0.7 0.373 0 / 1) 100%)',
|
||||
dimBgColor: 'color(display-p3 0.7 0.373 0 / 1)',
|
||||
textColor: 'light' as 'light' | 'dark',
|
||||
},
|
||||
{
|
||||
@@ -89,8 +95,7 @@ const aiBuilderStories = [
|
||||
{
|
||||
name: 'Lovable',
|
||||
logo: '/images/logos/publicity/lovable.svg',
|
||||
description:
|
||||
'We store embeddings in a PostgreSQL database. Supabase is a great partner for us as we scale.',
|
||||
description: 'We store embeddings in a PostgreSQL database.',
|
||||
slug: 'lovable',
|
||||
photo: '/images/logos/publicity/lovable-team.png',
|
||||
},
|
||||
@@ -125,7 +130,8 @@ function IconChip({
|
||||
}) {
|
||||
const isLight = story.textColor === 'light'
|
||||
const s = story as any
|
||||
const filter = s.iconFilter ?? (s.rawIcon ? undefined : isLight ? 'brightness(0) invert(1)' : 'brightness(0)')
|
||||
const filter =
|
||||
s.iconFilter ?? (s.rawIcon ? undefined : isLight ? 'brightness(0) invert(1)' : 'brightness(0)')
|
||||
return (
|
||||
<img
|
||||
src={story.icon}
|
||||
@@ -147,7 +153,7 @@ export function CustomerStoriesSection() {
|
||||
const active = customerStories[activeIdx]
|
||||
|
||||
return (
|
||||
<div className="py-24 flex flex-col gap-16 border-b border-border">
|
||||
<div className="py-24 flex flex-col gap-16">
|
||||
{/* Header row */}
|
||||
<div className="">
|
||||
<div className="mx-auto max-w-[var(--container-max-w,75rem)] px-6">
|
||||
@@ -184,10 +190,16 @@ export function CustomerStoriesSection() {
|
||||
{isActive && (
|
||||
<div className="flex flex-col gap-3 flex-1">
|
||||
<div>
|
||||
<p className="text-sm font-medium" style={{ color: isDark ? '#111' : 'white' }}>
|
||||
<p
|
||||
className="text-sm font-medium"
|
||||
style={{ color: isDark ? '#111' : 'white' }}
|
||||
>
|
||||
{story.name}
|
||||
</p>
|
||||
<p className="text-xs mt-0.5" style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.6)' }}>
|
||||
<p
|
||||
className="text-xs mt-0.5"
|
||||
style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.6)' }}
|
||||
>
|
||||
{story.tagline}
|
||||
</p>
|
||||
</div>
|
||||
@@ -198,8 +210,15 @@ export function CustomerStoriesSection() {
|
||||
"{story.quote}"
|
||||
</p>
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<img src={story.authorImg} alt={story.author} className="h-6 w-6 rounded-full object-cover shrink-0 ring-1 ring-white/30" />
|
||||
<p className="text-xs" style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.65)' }}>
|
||||
<img
|
||||
src={story.authorImg}
|
||||
alt={story.author}
|
||||
className="h-6 w-6 rounded-full object-cover shrink-0 ring-1 ring-white/30"
|
||||
/>
|
||||
<p
|
||||
className="text-xs"
|
||||
style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.65)' }}
|
||||
>
|
||||
{story.author}
|
||||
</p>
|
||||
</div>
|
||||
@@ -234,9 +253,9 @@ export function CustomerStoriesSection() {
|
||||
layout
|
||||
key={story.slug}
|
||||
onClick={() => setActiveIdx(index)}
|
||||
className="text-left flex flex-col items-start gap-8 overflow-hidden transition-opacity hover:opacity-90"
|
||||
className="text-left flex flex-col items-start gap-8 overflow-hidden"
|
||||
style={{
|
||||
background: isActive ? story.bgGradient : story.dimBgColor,
|
||||
background: story.bgGradient,
|
||||
borderRadius: 8,
|
||||
padding: isActive ? ACTIVE_PAD : `${ACTIVE_PAD}px ${INACTIVE_PAD}px`,
|
||||
boxShadow: isDark
|
||||
@@ -250,7 +269,8 @@ export function CustomerStoriesSection() {
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="flex flex-col gap-1.5 flex-1 w-[30rem]"
|
||||
layout
|
||||
className="flex flex-col gap-1.5 flex-1 w-[35rem]"
|
||||
initial={false}
|
||||
animate={{
|
||||
opacity: isActive ? 1 : 0,
|
||||
@@ -263,39 +283,46 @@ export function CustomerStoriesSection() {
|
||||
}}
|
||||
>
|
||||
{/* Top: company name + tagline */}
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm font-medium" style={{ color: isDark ? '#111' : 'white' }}>
|
||||
<motion.div layout className="flex flex-col gap-1">
|
||||
<motion.p
|
||||
layout
|
||||
className="text-sm font-medium"
|
||||
style={{ color: isDark ? '#111' : 'white' }}
|
||||
>
|
||||
{story.name}
|
||||
</p>
|
||||
<p
|
||||
</motion.p>
|
||||
<motion.p
|
||||
layout
|
||||
className="text-xs leading-relaxed text-pretty"
|
||||
style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.6)' }}
|
||||
>
|
||||
{story.tagline}
|
||||
</p>
|
||||
</div>
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
|
||||
{/* Bottom: quote + author */}
|
||||
<div className="flex flex-col gap-4 mt-auto">
|
||||
<p
|
||||
className="text-xl font-normal leading-relaxed text-pretty"
|
||||
<motion.div layout className="flex flex-col gap-4 mt-auto">
|
||||
<motion.p
|
||||
layout
|
||||
className="text-xl font-normal leading-relaxed text-balance"
|
||||
style={{ color: isDark ? '#222' : 'white' }}
|
||||
>
|
||||
"{story.quote}"
|
||||
</p>
|
||||
<div className="flex items-center gap-2.5 mb-4">
|
||||
</motion.p>
|
||||
<motion.div layout className="flex items-center gap-2.5 mb-4">
|
||||
<img
|
||||
src={story.authorImg}
|
||||
alt={story.author}
|
||||
className="h-7 w-7 rounded-full object-cover shrink-0 ring-1 ring-white/30"
|
||||
/>
|
||||
<p
|
||||
<motion.p
|
||||
layout
|
||||
className="text-xs"
|
||||
style={{ color: isDark ? '#888' : 'rgba(255,255,255,0.65)' }}
|
||||
>
|
||||
{story.author}
|
||||
</p>
|
||||
</div>
|
||||
</motion.p>
|
||||
</motion.div>
|
||||
<Link
|
||||
href={`/customers/${story.slug}`}
|
||||
className="text-xs underline"
|
||||
@@ -303,7 +330,7 @@ export function CustomerStoriesSection() {
|
||||
>
|
||||
Read the story →
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</motion.button>
|
||||
)
|
||||
@@ -314,7 +341,7 @@ export function CustomerStoriesSection() {
|
||||
{/* AI Builder stories */}
|
||||
<div className="mt-10">
|
||||
<div className="mx-auto max-w-[var(--container-max-w,75rem)] px-6">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-[420px_1fr] gap-8">
|
||||
<div className="grid grid-cols-1 items-end lg:grid-cols-[420px_1fr] gap-8">
|
||||
<div className="flex flex-col md:min-h-[320px] gap-4 justify-between">
|
||||
<h3 className="text-xl md:text-3xl text-foreground-lighter">
|
||||
Powering the next wave
|
||||
@@ -336,7 +363,7 @@ export function CustomerStoriesSection() {
|
||||
<Link
|
||||
key={story.slug}
|
||||
href={`/customers/${story.slug}`}
|
||||
className="group relative overflow-hidden rounded-lg w-full aspect-video border border-white/10 flex flex-col justify-end p-5"
|
||||
className="group relative overflow-hidden rounded-lg w-full aspect-[4/3] border border-white/10 flex flex-col justify-end p-5"
|
||||
>
|
||||
{/* Photo background */}
|
||||
<img
|
||||
@@ -345,7 +372,8 @@ export function CustomerStoriesSection() {
|
||||
className="absolute inset-0 w-full h-full object-cover select-none scale-[1.015]"
|
||||
/>
|
||||
{/* Dark gradient overlay — heavier at bottom */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/90 via-black/30 to-transparent" />
|
||||
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-[background-color] duration-300" />
|
||||
|
||||
{/* Logo + description at bottom */}
|
||||
<div className="relative z-10 flex flex-col gap-2">
|
||||
@@ -362,27 +390,6 @@ export function CustomerStoriesSection() {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Builder logo strip — full width below */}
|
||||
<div className="mt-8 pt-6 border-t border-muted flex flex-wrap items-center gap-x-8 gap-y-4">
|
||||
{[
|
||||
{ name: 'Lovable', logo: '/images/logos/publicity/lovable.svg' },
|
||||
{ name: 'Figma', logo: '/images/logos/publicity/figma.svg' },
|
||||
{ name: 'v0', logo: '/images/logos/publicity/v0.svg' },
|
||||
{ name: 'Bolt', logo: '/images/logos/publicity/bolt.svg' },
|
||||
{ name: 'Tempo', logo: '/images/logos/publicity/tempo.svg' },
|
||||
{ name: 'Gumloop', logo: '/images/logos/publicity/gumloop.svg' },
|
||||
{ name: 'Pika', logo: '/images/logos/publicity/pika.svg' },
|
||||
{ name: 'Udio', logo: '/images/logos/publicity/udio.svg' },
|
||||
].map((b) => (
|
||||
<img
|
||||
key={b.name}
|
||||
src={b.logo}
|
||||
alt={b.name}
|
||||
className="h-5 w-auto object-contain opacity-40 brightness-0 invert"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 25 25" fill="none">
|
||||
<path d="M22.2665 0.0844118L0.748068 6.35936C0.304553 6.48834 0 6.89441 0 7.35623V14.9592C0 15.8005 0.948607 16.2931 1.63676 15.808L20.9967 2.17135C21.203 2.02573 21.441 2.30532 21.2646 2.48588L1.72497 22.4649C1.08258 23.1222 1.54773 24.2289 2.46804 24.2289H8.78377C9.13492 24.2289 9.46277 24.0509 9.65415 23.7571L22.8656 3.4736C23.0012 3.26557 23.3207 3.427 23.2342 3.65916L16.0997 22.8285C15.8467 23.5075 16.3485 24.2289 17.0733 24.2289H23.8874C24.4607 24.2289 24.9259 23.7638 24.9259 23.1905V2.07815C24.9259 0.693517 23.5962 -0.303352 22.2673 0.0844118H22.2665Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 686 B |
Reference in new issue
Block a user