chore: add microinteractions to hero

This commit is contained in:
Francesco Sansalvadore committed 2023-05-16 12:46:36 +02:00
1 parent ae05af36f8
commit 45e2d3772a
6 files changed
+224 -175

No files matched your search

@@ -1,42 +0,0 @@
import { Button, Badge, IconArrowRight } from 'ui'
import SectionHeader from 'components/UI/SectionHeader'
import Solutions from 'data/Solutions.json'
import Link from 'next/link'
import SectionContainer from '../Layouts/SectionContainer'
import ProductIcon from '../ProductIcon'
import TextLink from '../TextLink'
const FeaturesOld = () => {
const IconSections = Object.values(Solutions).map((solution: any) => {
const { name, description, icon, label, url } = solution
if (solution.name === 'Realtime') return null
return (
<div key={name} className="mb-10 space-y-4 md:mb-0">
<div className="flex items-center">
<ProductIcon icon={icon} />
<dt className="text-scale-1200 ml-4 flex flex-row xl:flex-col">{name}</dt>
</div>
<p className="p">{description}</p>
{label && (
<div>
<Badge dot>{label}</Badge>
</div>
)}
{url && <TextLink label={label ? 'Get notified' : 'Learn more'} url={url} />}
</div>
)
})
return (
<SectionContainer className="space-y-16 pb-0">
<h3 className="h3">Build faster and focus on your products</h3>
<dl className="grid grid-cols-1 gap-y-4 sm:grid-cols-2 md:grid-cols-2 md:gap-16 lg:grid-cols-4 lg:gap-x-8 xl:gap-x-24">
{IconSections}
</dl>
</SectionContainer>
)
}
export default FeaturesOld
+12 -10
View File
@@ -8,6 +8,7 @@ import Image from 'next/image'
import SectionContainer from '../Layouts/SectionContainer'
import { motion } from 'framer-motion'
import BackedBy from '../BackedBy'
import { useBreakpoint } from 'common'
const Card = ({
classname,
@@ -27,7 +28,7 @@ const Card = ({
<Link href={url}>
<a
className={[
'relative col-span-1 lg:col-span-4 h-[460px] flex flex-col gap-5 lg:flex-row',
'relative col-span-1 lg:col-span-4 h-[360px] md:h-[460px] flex flex-col gap-5 lg:flex-row',
classname,
].join(' ')}
onClick={onClick}
@@ -95,13 +96,14 @@ const Features = () => {
)
}
}
const isSm = useBreakpoint(640)
return (
<SectionContainer className="space-y-8 max-w-7xl pt-4 md:!pt-0">
<dl className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-6 lg:grid-cols-6">
<Card
url={Solutions['database'].url}
title={'PostgreSQL Database'}
title={Solutions['database'].name}
subtitle="Every project is a full Postgres database, the world's most trusted relational database."
onClick={() => sendTelemetryEvent(name)}
image={
@@ -111,8 +113,8 @@ const Features = () => {
src="/images/index/database-dark-hover.jpg"
alt="Supabase Postgres Database, hover image with glow"
layout="fill"
objectPosition="50% 50%"
objectFit="cover"
objectPosition={isSm ? 'bottom' : '50% 50%'}
objectFit={isSm ? 'contain' : 'cover'}
quality={100}
/>
</motion.div>
@@ -120,8 +122,8 @@ const Features = () => {
src="/images/index/database-dark.jpg"
alt="Supabase Postgres Database"
layout="fill"
objectPosition="50% 50%"
objectFit="cover"
objectPosition={isSm ? 'bottom' : '50% 50%'}
objectFit={isSm ? 'contain' : 'cover'}
quality={100}
/>
</div>
@@ -196,8 +198,8 @@ const Features = () => {
src="/images/index/edge-dark-hover.jpg"
alt="Supabase Edge Functions feature, hover image with glow"
layout="fill"
objectPosition="50% 50%"
objectFit="cover"
objectPosition={isSm ? 'bottom' : '50% 50%'}
objectFit={isSm ? 'contain' : 'cover'}
quality={100}
/>
</motion.div>
@@ -205,8 +207,8 @@ const Features = () => {
src="/images/index/edge-dark.jpg"
alt="Supabase Edge Functions feature"
layout="fill"
objectPosition="50% 50%"
objectFit="cover"
objectPosition={isSm ? 'bottom' : '50% 50%'}
objectFit={isSm ? 'contain' : 'cover'}
quality={100}
/>
</div>
+46 -123
View File
@@ -1,139 +1,62 @@
import { useEffect, useRef } from 'react'
import Link from 'next/link'
import { Button, IconBookOpen } from 'ui'
import SectionContainer from '../Layouts/SectionContainer'
import styles from './hero.module.css'
import { useWindowSize } from 'react-use'
import BackedBy from '../BackedBy'
import { useTheme } from 'common'
import { motion } from 'framer-motion'
import HeroBackground from './HeroBackground'
const Hero = () => {
const divRef = useRef(null)
const { isDarkMode } = useTheme()
const { width } = useWindowSize()
useEffect(() => {
const newHeight =
width < 768 ? 100000 / width : width > 1800 ? 30000 / width : (70000 / width) * 2
if (divRef?.current) {
;(divRef.current as HTMLDivElement).style.height = `${Math.round(newHeight)}px`
console.log(width, newHeight)
}
}, [width])
return (
<div className="relative">
<SectionContainer className="md:py-16 lg:py-20">
<div className="relative">
<div className="mx-auto">
<div className="mx-auto max-w-2xl lg:col-span-6 lg:flex lg:items-center justify-center text-center">
<div className="lg:h-[50vh] lg:min-h-[300px] lg:max-h-[450px] flex flex-col items-center justify-center sm:mx-auto md:w-3/4 lg:mx-0 lg:w-full gap-4 lg:gap-8">
<div>
<motion.h1
initial={{ y: 10, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1, ease: [0, 0.13, 0.28, 1], delay: 0.2 }}
className="
const Hero = () => (
<div className="relative">
<SectionContainer className="md:py-16 lg:py-20">
<div className="relative">
<div className="mx-auto">
<div className="mx-auto max-w-2xl lg:col-span-6 lg:flex lg:items-center justify-center text-center">
<div className="lg:h-[50vh] lg:min-h-[300px] lg:max-h-[450px] flex flex-col items-center justify-center sm:mx-auto md:w-3/4 lg:mx-0 lg:w-full gap-4 lg:gap-8">
<div>
<motion.h1
initial={{ y: 10, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1, ease: [0.5, 0.01, 0.28, 1], delay: 0.2 }}
className="
text-scale-1200
text-4xl sm:text-5xl sm:leading-none lg:text-6xl
text-3xl sm:text-5xl sm:leading-none lg:text-6xl
xl:text-7xl
"
>
<span className="block">Build in a weekend.</span>
<span className="text-transparent bg-clip-text bg-gradient-to-br from-[#3ECF8E] via-[#3ECF8E] to-[#3E9BCF] block md:ml-0">
Scale to millions.
</span>
</motion.h1>
<p className="py-2 text-scale-1200 !mb-0 mt-1.5 text-sm sm:mt-5 sm:text-base lg:text-lg">
Supabase is an open source Firebase alternative for building secure and
performant Postgres backends with minimal configuration.
</p>
</div>
<div className="flex items-center gap-2">
<Link href="https://app.supabase.com" as="https://app.supabase.com" passHref>
<a>
<Button size="small" className="text-white">
Start your project
</Button>
</a>
</Link>
<Link href="/docs" as="/docs" passHref>
<a>
<Button size="small" type="default" icon={<IconBookOpen />}>
Documentation
</Button>
</a>
</Link>
</div>
<BackedBy className="hidden md:block" />
>
<span className="block">Build in a weekend.</span>
<span className="text-transparent bg-clip-text bg-gradient-to-br from-[#3ECF8E] via-[#3ECF8E] to-[#3E9BCF] block md:ml-0">
Scale to millions.
</span>
</motion.h1>
<p className="py-2 text-scale-1200 !mb-0 mt-1.5 text-sm sm:mt-5 sm:text-base lg:text-lg">
Supabase is an open source Firebase alternative for building secure and performant
Postgres backends with minimal configuration.
</p>
</div>
<div className="flex items-center gap-2">
<Link href="https://app.supabase.com" as="https://app.supabase.com" passHref>
<a>
<Button size="small" className="text-white">
Start your project
</Button>
</a>
</Link>
<Link href="/docs" as="/docs" passHref>
<a>
<Button size="small" type="default" icon={<IconBookOpen />}>
Documentation
</Button>
</a>
</Link>
</div>
<BackedBy className="hidden md:block" />
</div>
</div>
</div>
</SectionContainer>
<div
className={[
'absolute z-[-4] flex flex-col top-0 left-0 w-screen h-screen overflow-hidden pointer-events-none',
].join(' ')}
>
<div className="absolute w-screen h-screen">
<div className={['w-full top-0', styles['shape-gradient']].join(' ')} />
<div ref={divRef} className="w-full bg-scale-100" />
<div className={['2xl:-mt-52'].join(' ')}>
<svg
className={['', styles['triangle-svg']].join(' ')}
preserveAspectRatio="none"
width="100%"
height="100%"
viewBox="0 0 1680 915"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.16005e-05 -0.000998163L1680 0.129286V234L834.197 1068.2L-0.000248139 234.001L2.16005e-05 -0.000998163Z"
fill={isDarkMode ? '#171717' : '#fbfcfd'}
/>
</svg>
</div>
</div>
</div>
<div
className={[
'absolute top-0 left-0 w-full h-[600px] lg:h-[800px] overflow-hidden pointer-events-none',
styles['hero-container'],
].join(' ')}
>
<div className={['w-full h-full', styles['gradient']].join(' ')} />
<div className="absolute bottom-0 z-[-2] w-full h-full bg-gradient-to-t from-scale-100 to-transparent" />
<div
className={[
'relative -z-10 ![perspective:1200px] sm:![perspective:1200px] md:![perspective:1200px] lg:![perspective:1200px]',
].join(' ')}
>
<div
className="z-[100] absolute inset-0 [--gradient-stop-1:0px] [--gradient-stop-2:50%]"
style={{
background: 'linear-gradient(to top, rgba(0,0,0,0) 0px, #000000 50%)',
}}
></div>
<div
style={{
transform: 'rotateX(85deg)',
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
>
<div className={[styles['hero-grid-lines']].join(' ')}></div>
</div>
</div>
</div>
</div>
)
}
</SectionContainer>
<HeroBackground />
</div>
)
export default Hero
+166
View File
@@ -0,0 +1,166 @@
import React, { useEffect, useRef } from 'react'
import styles from './hero.module.css'
import { useWindowSize } from 'react-use'
import { useTheme } from 'common'
import { motion } from 'framer-motion'
const HeroBackground = () => {
const divRef = useRef(null)
const { isDarkMode } = useTheme()
const { width } = useWindowSize()
useEffect(() => {
const newHeight =
width < 768 ? 100000 / width : width > 1800 ? 30000 / width : (70000 / width) * 2
if (divRef?.current) {
;(divRef.current as HTMLDivElement).style.height = `${Math.round(newHeight)}px`
console.log(width, newHeight)
}
}, [width])
const svgTraceWidth = 1680
const svgTraceHeight = 915
const svgPath =
// 'M2.16005e-05 -0.000998163L1680 0.129286V234L834.197 1068.2L-0.000248139 234.001L2.16005e-05 -0.000998163Z'
'M2.16005e-05 -0.000998163L1680 0.129286V234L834.197 1068.2L-0.000248139 234.001L2.16005e-05 -0.000998163Z'
return (
<>
<div
className={[
'absolute z-[-4] flex flex-col top-0 left-0 w-screen h-screen overflow-hidden pointer-events-none',
].join(' ')}
>
<div className="absolute w-screen h-screen">
<div className={['w-full top-0 relative z-0', styles['shape-gradient']].join(' ')} />
<div ref={divRef} className="relative w-full bg-scale-100" />
<div className={['2xl:-mt-52'].join(' ')}>
<svg
className={['-mt-1 relative z-[-2]', styles['triangle-svg']].join(' ')}
preserveAspectRatio="none"
width="100%"
height="100%"
viewBox="0 0 1680 1069"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d={svgPath}
stroke="url(#electric-trace)"
strokeLinecap="round"
strokeWidth="2"
/>
<path
d={svgPath}
stroke="url(#electric-trace-right)"
strokeLinecap="round"
strokeWidth="2"
/>
<path d={svgPath} fill="var(--colors-scale1)" />
<defs>
{/*
// Animated trace
<motion.linearGradient
animate={{
x2: [
-svgTraceWidth / 2,
svgTraceWidth / 3,
// (svgTraceWidth / 5) * 2,
svgTraceWidth,
svgTraceWidth,
],
x1: [0, svgTraceWidth / 2, svgTraceWidth * 1.5, svgTraceWidth * 1.5],
y1: [
svgTraceHeight / 2,
svgTraceHeight / 2,
svgTraceHeight / 2,
svgTraceHeight / 2,
],
y2: [
svgTraceHeight / 2,
svgTraceHeight / 2,
svgTraceHeight / 2,
svgTraceHeight / 2,
],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: 'linear',
delay: 4,
}}
id="electric-trace"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#3ecf8e" stopOpacity="0" />
<stop stopColor="#3ecf8e" stopOpacity="0.8" />
<stop offset="1" stopColor="#3E9BCF" stopOpacity="0" />
</motion.linearGradient> */}
<linearGradient
x1={svgTraceWidth / 2 - 100}
y1={svgTraceHeight / 2}
x2={0}
y2={svgTraceHeight / 2}
id="electric-trace"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#3ecf8e" stopOpacity="0" />
<stop stopColor="#3ecf8e" stopOpacity="0.8" />
<stop offset="1" stopColor="#3E9BCF" stopOpacity="0" />
</linearGradient>
<linearGradient
x1={svgTraceWidth + 100}
y1={svgTraceHeight / 2}
x2={svgTraceWidth / 2}
y2={svgTraceHeight / 2}
id="electric-trace-right"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#3ecf8e" stopOpacity="0" />
<stop stopColor="#3ecf8e" stopOpacity="0.8" />
<stop offset="1" stopColor="#3E9BCF" stopOpacity="0" />
</linearGradient>
</defs>
</svg>
</div>
</div>
</div>
<div
className={[
'absolute top-0 left-0 w-full h-[600px] lg:h-[800px] overflow-hidden pointer-events-none',
styles['hero-container'],
].join(' ')}
>
<div className={['w-full h-full', styles['gradient']].join(' ')} />
<div className="absolute bottom-0 z-[-2] w-full h-full bg-gradient-to-t from-scale-100 to-transparent" />
<div
className={[
'relative -z-10 ![perspective:1200px] sm:![perspective:1200px] md:![perspective:1200px] lg:![perspective:1200px]',
].join(' ')}
>
<div
className="z-[100] absolute inset-0 [--gradient-stop-1:0px] [--gradient-stop-2:50%]"
style={{
background: 'linear-gradient(to top, rgba(0,0,0,0) 0px, #000000 50%)',
}}
></div>
<div
style={{
transform: 'rotateX(85deg)',
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
>
<div className={[styles['hero-grid-lines']].join(' ')}></div>
</div>
</div>
</div>
</>
)
}
export default HeroBackground
Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 102 KiB