|
1 | 1 | import Link from 'next/link' |
2 | | -import React from 'react' |
| 2 | +import React, { useEffect } from 'react' |
3 | 3 | import { cn } from 'ui' |
4 | 4 |
|
| 5 | +import styles from './ai-builders-logos.module.css' |
| 6 | + |
5 | 7 | const logos = [ |
6 | | - { |
7 | | - image: `/images/logos/publicity/lovable.svg`, |
8 | | - alt: 'lovable', |
9 | | - name: 'lovable', |
10 | | - href: 'https://lovable.dev/', |
11 | | - }, |
12 | | - { |
13 | | - image: `/images/logos/publicity/bolt.svg`, |
14 | | - alt: 'bolt', |
15 | | - name: 'bolt', |
16 | | - href: 'https://bolt.new', |
17 | | - }, |
18 | | - { |
19 | | - image: `/images/logos/publicity/v0.svg`, |
20 | | - alt: 'v0', |
21 | | - name: 'v0', |
22 | | - href: 'https://v0.dev', |
23 | | - }, |
24 | | - { |
25 | | - image: `/images/logos/publicity/figma.svg`, |
26 | | - alt: 'figma', |
27 | | - name: 'figma', |
28 | | - href: 'https://www.figma.com/make/', |
29 | | - }, |
30 | | - { |
31 | | - image: `/images/logos/publicity/tempo.svg`, |
32 | | - alt: 'tempo', |
33 | | - name: 'tempo', |
34 | | - href: 'https://tempo.new', |
35 | | - }, |
36 | | - { |
37 | | - image: `/images/logos/publicity/gumloop.svg`, |
38 | | - alt: 'gumloop', |
39 | | - name: 'gumloop', |
40 | | - href: 'https://gumloop.com', |
41 | | - }, |
42 | | - { |
43 | | - image: `/images/logos/publicity/co-com.svg`, |
44 | | - alt: 'co.com', |
45 | | - name: 'co-com', |
46 | | - href: 'https://co.dev', |
47 | | - }, |
| 8 | + [ |
| 9 | + { |
| 10 | + image: `/images/logos/publicity/v0.svg`, |
| 11 | + alt: 'v0', |
| 12 | + name: 'v0', |
| 13 | + href: 'https://v0.dev', |
| 14 | + }, |
| 15 | + { |
| 16 | + image: `/images/logos/publicity/lovable.svg`, |
| 17 | + alt: 'lovable', |
| 18 | + name: 'lovable', |
| 19 | + href: 'https://lovable.dev/', |
| 20 | + }, |
| 21 | + { |
| 22 | + image: `/images/logos/publicity/bolt.svg`, |
| 23 | + alt: 'bolt', |
| 24 | + name: 'bolt', |
| 25 | + href: 'https://bolt.new', |
| 26 | + }, |
| 27 | + ], |
| 28 | + [ |
| 29 | + { |
| 30 | + image: `/images/logos/publicity/figma.svg`, |
| 31 | + alt: 'figma', |
| 32 | + name: 'figma', |
| 33 | + href: 'https://www.figma.com/make/', |
| 34 | + }, |
| 35 | + { |
| 36 | + image: `/images/logos/publicity/tempo.svg`, |
| 37 | + alt: 'tempo', |
| 38 | + name: 'tempo', |
| 39 | + href: 'https://tempo.new', |
| 40 | + }, |
| 41 | + { |
| 42 | + image: `/images/logos/publicity/gumloop.svg`, |
| 43 | + alt: 'gumloop', |
| 44 | + name: 'gumloop', |
| 45 | + href: 'https://gumloop.com', |
| 46 | + }, |
| 47 | + ], |
| 48 | + // { |
| 49 | + // image: `/images/logos/publicity/co-com.svg`, |
| 50 | + // alt: 'co.com', |
| 51 | + // name: 'co-com', |
| 52 | + // href: 'https://co.dev', |
| 53 | + // }, |
48 | 54 | ] |
49 | 55 |
|
50 | 56 | interface Props { |
51 | 57 | className?: string |
52 | 58 | } |
53 | 59 |
|
| 60 | +const stagger = 0.1 |
| 61 | + |
| 62 | +// duration in ms |
| 63 | +const duration = 5000 |
| 64 | + |
54 | 65 | const EnterpriseLogos: React.FC<Props> = ({ className }) => { |
| 66 | + const [index, setIndex] = React.useState(0) |
| 67 | + const [animate, setAnimate] = React.useState(false) |
| 68 | + |
| 69 | + const currentLogos = logos[index].slice(0, 3) |
| 70 | + const logosNext = logos[(index + 1) % logos.length].slice(0, 3) |
| 71 | + |
| 72 | + useEffect(() => { |
| 73 | + const id = setTimeout(() => { |
| 74 | + setAnimate(true) |
| 75 | + }, 500) |
| 76 | + |
| 77 | + return () => { |
| 78 | + clearTimeout(id) |
| 79 | + } |
| 80 | + }, []) |
| 81 | + |
| 82 | + useEffect(() => { |
| 83 | + if (!animate) { |
| 84 | + return |
| 85 | + } |
| 86 | + |
| 87 | + function loop() { |
| 88 | + setIndex((index) => (index + 1) % logos.length) |
| 89 | + } |
| 90 | + |
| 91 | + const interval = setInterval(loop, duration) |
| 92 | + |
| 93 | + return () => { |
| 94 | + clearInterval(interval) |
| 95 | + } |
| 96 | + }, [animate]) |
| 97 | + |
55 | 98 | return ( |
56 | | - <div |
| 99 | + <div className={cn('grid place-items-center w-full', className)}> |
| 100 | + <div |
| 101 | + key={`${index}-exit`} |
| 102 | + className="grid grid-cols-3 items-center text-center justify-center sm:flex gap-4 lg:gap-8" |
| 103 | + style={{ |
| 104 | + gridArea: '1 / 1', |
| 105 | + }} |
| 106 | + > |
| 107 | + {currentLogos.map((logo, idx) => ( |
| 108 | + <Logo |
| 109 | + key={`ent-logo-${logo.name}-${idx}`} |
| 110 | + logo={logo} |
| 111 | + state="exit" |
| 112 | + animate={animate} |
| 113 | + index={idx} |
| 114 | + stagger={stagger} |
| 115 | + /> |
| 116 | + ))} |
| 117 | + </div> |
| 118 | + |
| 119 | + {animate && ( |
| 120 | + <div |
| 121 | + key={`${index}-enter`} |
| 122 | + className="items-center text-center justify-center flex-wrap flex gap-4 lg:gap-8" |
| 123 | + style={{ |
| 124 | + gridArea: '1 / 1', |
| 125 | + }} |
| 126 | + > |
| 127 | + {logosNext.map((logo, idx) => ( |
| 128 | + <Logo |
| 129 | + key={`ent-logo-${logo.name}-${idx}`} |
| 130 | + logo={logo} |
| 131 | + state="enter" |
| 132 | + animate={animate} |
| 133 | + index={idx} |
| 134 | + stagger={stagger} |
| 135 | + /> |
| 136 | + ))} |
| 137 | + </div> |
| 138 | + )} |
| 139 | + </div> |
| 140 | + ) |
| 141 | +} |
| 142 | + |
| 143 | +const Logo = ({ |
| 144 | + logo, |
| 145 | + state, |
| 146 | + animate, |
| 147 | + index, |
| 148 | + stagger, |
| 149 | +}: { |
| 150 | + logo: (typeof logos)[0][0] |
| 151 | + state: 'enter' | 'exit' |
| 152 | + animate: boolean |
| 153 | + index: number |
| 154 | + stagger: number |
| 155 | +}) => { |
| 156 | + return ( |
| 157 | + <Link |
| 158 | + href={logo.href} |
| 159 | + target="_blank" |
57 | 160 | className={cn( |
58 | | - 'flex lg:grid grid-cols-2 xl:flex flex-nowrap gap-4 md:gap-8 lg:gap-4 2xl:gap-4', |
59 | | - className |
| 161 | + 'h-8 lg:h-12 w-max mx-auto hover:opacity-100 opacity-80 transition-opacity', |
| 162 | + styles.logo |
60 | 163 | )} |
| 164 | + data-state={state} |
| 165 | + data-animate={animate} |
| 166 | + style={ |
| 167 | + { |
| 168 | + '--delay': `${index * stagger}s`, |
| 169 | + } as React.CSSProperties |
| 170 | + } |
61 | 171 | > |
62 | | - {logos.map((logo) => ( |
63 | | - <Link |
64 | | - href={logo.href} |
65 | | - target="_blank" |
66 | | - key={`ent-logo-${logo.name}`} |
67 | | - className="h-12 lg:h-12 w-max hover:opacity-100 opacity-80 transition-opacity" |
68 | | - > |
69 | | - <img |
70 | | - src={logo.image} |
71 | | - alt={logo.alt} |
72 | | - className=" |
73 | | - w-auto block |
74 | | - h-10 !min-h-10 |
75 | | - md:h-10 md:!min-h-10 |
76 | | - lg:h-7 lg:!min-h-7 |
77 | | - 2xl:h-10 2xl:!min-h-10 |
78 | | - " |
79 | | - draggable={false} |
80 | | - /> |
81 | | - </Link> |
82 | | - ))} |
83 | | - </div> |
| 172 | + <img |
| 173 | + src={logo.image} |
| 174 | + alt={logo.alt} |
| 175 | + className=" |
| 176 | + w-auto block |
| 177 | + h-10 !min-h-10 |
| 178 | + md:h-10 md:!min-h-10 |
| 179 | + lg:h-7 lg:!min-h-7 |
| 180 | + 2xl:h-10 2xl:!min-h-10 |
| 181 | + " |
| 182 | + draggable={false} |
| 183 | + /> |
| 184 | + </Link> |
84 | 185 | ) |
85 | 186 | } |
86 | 187 |
|
|
0 commit comments