Skip to content

Commit 9c5da50

Browse files
feat: clean up + text animation + mobile improvements (#2562)
1 parent 4205615 commit 9c5da50

File tree

12 files changed

+84
-30
lines changed

12 files changed

+84
-30
lines changed

apps/web/src/app/components/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const metadata: Metadata = {
2424
export default async function ComponentsPage() {
2525
return (
2626
<PageWrapper>
27-
<div className="pointer-events-none absolute inset-0 flex justify-center">
27+
<div className="pointer-events-none absolute inset-0 flex justify-center [mask-image:linear-gradient(to_bottom,transparent_0%,black_4%,black_96%,transparent_100%)]">
2828
<div className="hidden h-full w-full max-w-7xl grid-cols-2 gap-4 px-4 lg:grid">
2929
<div className="border-r-slate-3 border-l border-l-slate-4" />
3030
<div className="border-r border-r-slate-4" />
@@ -41,8 +41,8 @@ export default async function ComponentsPage() {
4141
</p>
4242
</div>
4343
<div className="relative grid grid-cols-1 gap-x-4 px-1 pb-10 md:grid-cols-2 md:px-0 lg:grid-cols-3">
44-
<div className="-translate-x-1/2 absolute top-0 left-1/2 h-px w-[100dvw] border-slate-4 border-t" />
45-
<div className="-translate-x-1/2 absolute bottom-0 left-1/2 h-px w-[100dvw] border-slate-4 border-b" />
44+
<div className="-translate-x-1/2 absolute top-0 left-1/2 h-px w-[100dvw] border-slate-4 border-t xl:[mask-image:linear-gradient(to_right,transparent_0%,black_10%,black_90%,transparent_100%)]" />
45+
<div className="-translate-x-1/2 absolute bottom-0 left-1/2 h-px w-[100dvw] border-slate-4 border-b xl:[mask-image:linear-gradient(to_right,transparent_0%,black_10%,black_90%,transparent_100%)]" />
4646
{componentsStructure.map((category, index) => {
4747
const slug = slugify(category.name);
4848
const Illustration = dynamic(

apps/web/src/app/layout.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Analytics } from '@vercel/analytics/react';
22
import type { Metadata } from 'next';
33
import '@/styles/globals.css';
44
import localFont from 'next/font/local';
5+
import { Topbar } from '@/components/topbar';
56

67
const inter = localFont({
78
display: 'swap',
@@ -95,6 +96,9 @@ export default function RootLayout({
9596
<script src="/js/web-streams-polyfill.js" />
9697
</head>
9798
<body className="h-screen-ios overflow-x-hidden bg-black font-sans text-slate-11 text-sm selection:bg-cyan-5 selection:text-cyan-12">
99+
<div className="relative mx-auto flex flex-col justify-between px-2 md:max-w-7xl md:px-4">
100+
<Topbar />
101+
</div>
98102
{children}
99103
<Analytics />
100104
</body>

apps/web/src/app/page.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,9 @@ import PlaygroundSection from '@/components/sections/playground';
66
import PrimitivesSection from '@/components/sections/primitives';
77
import TestimonialSection from '@/components/sections/testimonial';
88
import ToolsSection from '@/components/sections/tools';
9-
import { Topbar } from '@/components/topbar';
109

1110
const Home = () => (
1211
<main className="max-lg:overflow-x-clip">
13-
<div className="relative mx-auto flex flex-col justify-between px-2 md:max-w-7xl md:px-4">
14-
<Topbar />
15-
</div>
1612
<HeroSection />
1713
<div className="relative mx-auto flex flex-col justify-between px-2 md:max-w-7xl md:px-4">
1814
<PlaygroundSection />

apps/web/src/components/menu.tsx

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use client';
22

33
import classnames from 'classnames';
4-
import { MenuIcon } from 'lucide-react';
54
import Link from 'next/link';
65
import { usePathname } from 'next/navigation';
76
import * as React from 'react';
@@ -16,6 +15,16 @@ interface MenuItemProps {
1615

1716
const GITHUB_URL = 'https://github.com/resend/react-email';
1817

18+
async function getRepoStarCount() {
19+
const res = await fetch('https://api.github.com/repos/resend/react-email');
20+
const data = await res.json();
21+
const starCount = data.stargazers_count;
22+
if (starCount > 999) {
23+
return `${(starCount / 1000).toFixed(1)}K`;
24+
}
25+
return starCount;
26+
}
27+
1928
function MenuItem({ className, children, href, onClick }: MenuItemProps) {
2029
const pathname = usePathname();
2130
const [, activeItem] = pathname?.split('/') ?? [];
@@ -67,10 +76,26 @@ function MenuItems({ onItemClick }: { onItemClick: () => void }) {
6776
);
6877
}
6978

79+
function MenuIcon() {
80+
return (
81+
<div className="flex flex-col gap-2">
82+
{Array.from({ length: 2 }).map((_, index) => (
83+
<div key={index} className="w-5 h-px rounded-full bg-slate-11" />
84+
))}
85+
</div>
86+
);
87+
}
88+
7089
function SocialIcons({ onItemClick }: { onItemClick: () => void }) {
90+
const [starCount, setStarCount] = React.useState<string | number>('');
91+
92+
React.useEffect(() => {
93+
getRepoStarCount().then(setStarCount);
94+
}, []);
95+
7196
return (
7297
<MenuItem
73-
className="w-8 justify-center"
98+
className="w-fit gap-1.5 justify-center px-2"
7499
href={GITHUB_URL}
75100
onClick={onItemClick}
76101
>
@@ -85,6 +110,7 @@ function SocialIcons({ onItemClick }: { onItemClick: () => void }) {
85110
fill="currentColor"
86111
/>
87112
</svg>
113+
{starCount && <span>{starCount}</span>}
88114
</MenuItem>
89115
);
90116
}
@@ -110,7 +136,8 @@ export function Menu() {
110136
<SocialIcons onItemClick={handleItemClick} />
111137
</ul>
112138
</nav>
113-
<nav className="relative flex items-center gap-2 md:hidden">
139+
<nav className="relative flex items-center gap-1 md:hidden">
140+
<SocialIcons onItemClick={handleItemClick} />
114141
<ul className="flex gap-2">
115142
<Drawer.Root
116143
onOpenChange={setDrawerOpen}
@@ -121,14 +148,12 @@ export function Menu() {
121148
<MenuIcon />
122149
</Drawer.Trigger>
123150
<Drawer.Portal>
124-
<Drawer.Overlay className="-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 z-[2] h-[200dvh] w-[200dvw] bg-slate-800/50" />
125-
<Drawer.Content className="fixed right-0 bottom-0 left-0 z-50 flex h-fit flex-col gap-8 rounded-t-xl bg-black p-8 pt-10">
151+
<Drawer.Overlay className="-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 z-50 h-[200dvh] w-[200dvw] bg-black/80" />
152+
<Drawer.Content className="fixed right-0 bottom-0 left-0 z-[51] flex h-fit flex-col gap-8 rounded-t-xl bg-black border-t border-slate-5 p-8 pt-10">
153+
<Drawer.Title className="sr-only">Menu</Drawer.Title>
126154
<ul className="flex w-full flex-col items-start gap-4">
127155
<MenuItems onItemClick={handleItemClick} />
128156
</ul>
129-
<ul className="flex w-fit gap-2">
130-
<SocialIcons onItemClick={handleItemClick} />
131-
</ul>
132157
</Drawer.Content>
133158
</Drawer.Portal>
134159
</Drawer.Root>

apps/web/src/components/page-wrapper.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Footer } from '@/components/footer';
2-
import { Topbar } from '@/components/topbar';
32

43
interface PageWrapperProps {
54
children: React.ReactNode;
@@ -15,7 +14,6 @@ export function PageWrapper({ children, className = '' }: PageWrapperProps) {
1514
className={`relative mx-auto flex min-h-[100dvh] flex-col justify-between px-2 md:max-w-7xl md:px-4 ${className}`}
1615
vaul-drawer-wrapper=""
1716
>
18-
<Topbar />
1917
{children}
2018
<Footer />
2119
</div>

apps/web/src/components/sections/hero.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import { Text } from '@/components/text';
1212
// Dynamically import Tower component to avoid SSR issues with Three.js
1313
const Tower = dynamic(() => import('@/webgl/tower').then((mod) => mod.Tower), {
1414
ssr: false,
15-
loading: () => (
16-
<div className="w-full h-full flex items-center justify-center">
17-
<div className="text-white/30">Loading...</div>
18-
</div>
19-
),
2015
});
2116

2217
const HeroSection = () => {
@@ -56,7 +51,7 @@ const HeroSection = () => {
5651
/>
5752
</div>
5853
<Heading
59-
className="!text-white/80 relative mb-8 text-center lg:text-left before:absolute before:top-0 before:left-0 before:w-full before:animate-[shine_2s_ease-in-out] before:bg-[length:200%] before:bg-shine before:bg-clip-text before:text-transparent before:content-['The_next_generation_of_writing_emails'] before:select-none before:pointer-events-none text-balance"
54+
className="text-white/80 relative mb-8 text-center lg:text-left before:absolute before:top-0 before:left-0 before:w-full before:animate-[shine_1.5s_ease-in-out] before:bg-[length:225%] before:bg-shine before:bg-clip-text before:text-transparent before:content-['The_next_generation_of_writing_emails'] before:select-none before:pointer-events-none text-balance"
6055
weight="medium"
6156
size="10"
6257
>

apps/web/src/components/sections/integration.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const IntegrationSection = () => {
1212

1313
return (
1414
<section className="relative pt-12 pb-28 md:pb-80 px-6">
15-
<div className="space-y-16">
15+
<div className="space-y-12 md:space-y-16">
1616
<div className="max-w-full text-center space-y-4">
1717
<Heading
1818
size="8"

apps/web/src/components/sections/playground/code-preview.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import * as Tabs from '@radix-ui/react-tabs';
44
import { render } from '@react-email/render';
5+
import classNames from 'classnames';
56
import React from 'react';
67
import { CodeBlock } from '@/components/code-block';
78
import { CopyCode } from '@/components/copy-code';
89
import { IconFile } from '@/components/icons/icon-file';
10+
import { useScroll } from '@/utils/use-scroll';
911
import WelcomeEmail from './code-example';
1012

1113
type Tab = {
@@ -74,6 +76,8 @@ const CodePreviewHeader = ({
7476
const CodePreviewContent = ({ tabs }: { tabs: Tab[] }) => {
7577
const [emailOutput, setEmailOutput] = React.useState<string | null>(null);
7678

79+
const { isScrolling } = useScroll();
80+
7781
React.useEffect(() => {
7882
const renderEmail = async () => {
7983
const html = await render(<WelcomeEmail />);
@@ -90,7 +94,10 @@ const CodePreviewContent = ({ tabs }: { tabs: Tab[] }) => {
9094
<Tabs.Content
9195
key={tab.value}
9296
value={tab.value}
93-
className="h-[400px] md:h-[600px] overflow-auto"
97+
className={classNames(
98+
'h-[400px] md:h-[600px] overflow-auto',
99+
isScrolling && 'pointer-events-none',
100+
)}
94101
style={{
95102
maskImage: `
96103
linear-gradient(to bottom, transparent 0%, black 4%, black 96%, transparent 100%),

apps/web/src/components/sections/primitives.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Text } from '@/components/text';
44

55
const PrimitivesSection = () => {
66
return (
7-
<section className="relative my-24 md:my-40 md:py-20 space-y-16 max-md:px-6">
7+
<section className="relative md:my-40 md:py-20 space-y-16 max-md:px-6">
88
<div className="flex flex-col gap-4">
99
<Heading size="8" weight="medium" className="text-white/80">
1010
Battle-tested Primitives

apps/web/src/utils/spam-assassin/parse-pointing-table-rows.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ export const parsePointingTableRows = (response: string) => {
4040
}
4141

4242
if (match?.groups === undefined) {
43-
console.log(line);
4443
throw new Error('Could not match the columns in the row', {
4544
cause: {
4645
line,
@@ -57,7 +56,6 @@ export const parsePointingTableRows = (response: string) => {
5756
}
5857
const parsedPoints = Number.parseFloat(pts);
5958
if (Number.isNaN(parsedPoints)) {
60-
console.log(line);
6159
throw new Error('could not parse points to insert into rows array', {
6260
cause: {
6361
line,

0 commit comments

Comments
 (0)