Compare commits

...

5 Commits

Author SHA1 Message Date
Trisha Lim
2870ec377d Reuse FeatureCard on Coming Soon section 2024-11-25 11:03:23 +00:00
Trisha Lim
7966809431 Renamed LabelledFeatureIcon to FeatureCard 2024-11-25 10:46:23 +00:00
Trisha Lim
9a955b5138 Make coming soon section 4-col 2024-11-22 20:03:43 +00:00
Trisha Lim
4e59f1e6cd Add cols prop to GappedGrid component 2024-11-22 20:01:37 +00:00
Trisha Lim
0c54143c75 Create card component 2024-11-22 19:58:35 +00:00
13 changed files with 106 additions and 83 deletions

View File

@@ -0,0 +1,12 @@
import { clsx } from "clsx";
export function Card({
children,
className,
}: { children: React.ReactNode; className?: string }) {
return (
<div className={clsx(className, "border rounded-xl shadow-sm")}>
{children}
</div>
);
}

View File

@@ -1,16 +1,16 @@
import clsx from "clsx";
import { ReactNode } from "react";
import { Card } from "../atoms/Card";
export function GridCard(props: { children: ReactNode; className?: string }) {
return (
<div
<Card
className={clsx(
"col-span-2 p-4 [&>h4]:mt-0 [&>h3]:mt-0 [&>:last-child]:mb-0",
"border rounded-xl shadow-sm",
props.className,
)}
>
{props.children}
</div>
</Card>
);
}

View File

@@ -0,0 +1,36 @@
import clsx from "clsx";
import { LucideIcon } from "lucide-react";
import { Card } from "../atoms/Card";
import { Prose } from "./Prose";
export function FeatureCard({
label,
icon: Icon,
explanation,
children,
className,
}: {
label: React.ReactNode;
icon?: LucideIcon;
explanation?: React.ReactNode;
children?: React.ReactNode;
className?: string;
}) {
return (
<Card className={clsx(className, "p-4")}>
{Icon && (
<Icon
className="size-8 text-blue p-1.5 rounded-lg bg-blue-50 dark:text-blue-500 dark:bg-stone-900 mb-2.5 md:size-10"
strokeWidth={1.5}
strokeLinecap="butt"
size={80}
/>
)}
<div className="text-stone-900 font-medium md:text-base dark:text-stone-100 mb-2">
{label}
</div>
{explanation && <Prose>{explanation}</Prose>}
{children}
</Card>
);
}

View File

@@ -6,15 +6,23 @@ export function GappedGrid({
children,
className,
title,
cols = 3,
}: {
children: ReactNode;
className?: string;
title?: string;
cols?: 3 | 4;
}) {
const colsClassName =
cols === 3
? "md:grid-cols-4 lg:grid-cols-6"
: "sm:grid-cols-2 lg:grid-cols-4";
return (
<div
className={clsx(
"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4 lg:gap-8",
"grid grid-cols-2 gap-4 lg:gap-8",
colsClassName,
"items-stretch",
className,
)}

View File

@@ -1,37 +0,0 @@
import clsx from "clsx";
import { LucideIcon } from "lucide-react";
import { Prose } from "./Prose";
export function LabelledFeatureIcon({
label,
icon: Icon,
explanation,
className,
}: {
label: string;
icon: LucideIcon;
explanation: React.ReactNode;
className?: string;
}) {
return (
<div
className={clsx(
className,
"text-base",
"rounded-xl",
"border p-4 shadow-sm",
)}
>
<Icon
className="size-8 text-blue p-1.5 rounded-lg bg-blue-50 dark:text-blue-500 dark:bg-stone-900 mb-2.5 md:size-10"
strokeWidth={1.5}
strokeLinecap="butt"
size={80}
/>
<div className="text-stone-900 font-medium md:text-base dark:text-stone-100 mb-2">
{label}
</div>
<Prose>{explanation}</Prose>
</div>
);
}

View File

@@ -1,5 +1,6 @@
"use client";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -22,7 +23,7 @@ function Iframe(
const { src, user } = props;
return (
<div className="relative col-span-2 w-full border rounded-xl shadow-sm overflow-hidden lg:col-span-2 dark:bg-black">
<Card className="relative col-span-2 w-full overflow-hidden lg:col-span-2 dark:bg-black">
<iframe
{...props}
src={src}
@@ -31,7 +32,7 @@ function Iframe(
height="390"
allowFullScreen
/>
</div>
</Card>
);
}

View File

@@ -1,3 +1,4 @@
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -42,8 +43,8 @@ export function CollaborationFeaturesSection() {
<GappedGrid>
{data.map(({ title, description, codeSample: CodeSample }) => (
<div
className="col-span-2 border rounded-xl shadow-sm pt-4 px-4 flex flex-col gap-3"
<Card
className="col-span-2 pt-4 px-4 flex flex-col gap-3"
key={title}
>
<div>
@@ -57,7 +58,7 @@ export function CollaborationFeaturesSection() {
<pre className="flex-1 text-sm border-t border-x rounded-t-lg bg-stone-50 dark:bg-stone-925">
<CodeSample />
</pre>
</div>
</Card>
))}
</GappedGrid>
</div>

View File

@@ -3,9 +3,8 @@ import CursorsAndCaretsDescription from "@/app/(home)/toolkit/cursorsAndCarets.m
import TwoWaySyncDescription from "@/app/(home)/toolkit/twoWaySync.mdx";
import VideoPresenceCallsDescription from "@/app/(home)/toolkit/videoPresenceCalls.mdx";
import { CodeRef } from "gcmp-design-system/src/app/components/atoms/CodeRef";
import { GridCard } from "gcmp-design-system/src/app/components/atoms/GridCard";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { P } from "gcmp-design-system/src/app/components/atoms/Paragraph";
import { FeatureCard } from "gcmp-design-system/src/app/components/molecules/FeatureCard";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -15,39 +14,40 @@ export function ComingSoonSection() {
<div>
<SectionHeader title="More features coming soon" />
<GappedGrid>
<GridCard>
<H3>Cursors & carets</H3>
<P className="text-lg">Ready-made spatial presence.</P>
<GappedGrid cols={4}>
<FeatureCard className="p-4" label={<h3>Cursors & carets</h3>}>
<P>Ready-made spatial presence.</P>
<Prose size="sm">
<CursorsAndCaretsDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>Two-way sync to your DB</H3>
<P className="text-lg">Add Jazz to an existing app.</P>
<FeatureCard className="p-4" label={<h3>Two-way sync to your DB</h3>}>
<P>Add Jazz to an existing app.</P>
<Prose size="sm">
<TwoWaySyncDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>Video presence & calls</H3>
<P className="text-lg">Stream and record audio & video.</P>
<FeatureCard className="p-4" label={<h3>Video presence & calls</h3>}>
<P>Stream and record audio & video.</P>
<Prose size="sm">
<VideoPresenceCallsDescription />
</Prose>
</GridCard>
</FeatureCard>
<GridCard>
<H3>
<CodeRef>CoPlainText</CodeRef> & <CodeRef>CoRichText</CodeRef>
</H3>
<FeatureCard
className="p-4"
label={
<h3>
<CodeRef>CoPlainText</CodeRef> & <CodeRef>CoRichText</CodeRef>
</h3>
}
>
<Prose size="sm">
<CoPlainTextDescription />
</Prose>
</GridCard>
</FeatureCard>
</GappedGrid>
</div>
);

View File

@@ -1,10 +1,11 @@
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
export function EarlyAdopterSection() {
return (
<div className="border rounded-xl shadow-sm p-4 md:py-16">
<Card className="p-4 md:py-16">
<div className="lg:max-w-3xl md:text-center mx-auto space-y-6">
<p className="uppercase text-blue tracking-widest text-sm font-medium dark:text-stone-400">
Become an early adopter
@@ -31,6 +32,6 @@ export function EarlyAdopterSection() {
</Button>
</div>
</div>
</div>
</Card>
);
}

View File

@@ -1,3 +1,4 @@
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { LockKeyholeIcon } from "lucide-react";
@@ -64,7 +65,7 @@ function Illustration() {
export function EncryptionSection() {
return (
<div className="border rounded-xl bg-white shadow-sm overflow-hidden dark:bg-stone-925">
<Card className="overflow-hidden dark:bg-stone-925">
<div className="flex grid md:grid-cols-3 md:gap-3">
<div className="md:col-span-2 px-4 pb-4 md:p-8">
<H3 className="mb-0 text-balance">
@@ -86,6 +87,6 @@ export function EncryptionSection() {
<Illustration />
</div>
</div>
</Card>
);
}

View File

@@ -1,6 +1,7 @@
import { ServerWorkersDiagram } from "@/components/home/ServerWorkersDiagram";
import { ClerkLogo } from "@/components/icons/ClerkLogo";
import { Button } from "gcmp-design-system/src/app/components/atoms/Button";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H3 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { Prose } from "gcmp-design-system/src/app/components/molecules/Prose";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
@@ -124,10 +125,7 @@ export function FeaturesSection() {
<div className="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-6 gap-4 lg:gap-8">
{features.map(({ title, icon: Icon, description, illustration }) => (
<div
key={title}
className="col-span-2 border rounded-xl shadow-sm overflow-hidden"
>
<Card key={title} className="col-span-2 overflow-hidden">
<div className="h-48 flex w-full items-center justify-center">
{illustration}
</div>
@@ -137,7 +135,7 @@ export function FeaturesSection() {
</h3>
<Prose size="sm">{description}</Prose>
</div>
</div>
</Card>
))}
<div className="border p-4 sm:p-8 shadow-sm rounded-xl col-span-2 sm:col-span-4 space-y-5">

View File

@@ -1,4 +1,5 @@
import { clsx } from "clsx";
import { Card } from "gcmp-design-system/src/app/components/atoms/Card";
import { H2 } from "gcmp-design-system/src/app/components/atoms/Headings";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import CodeStepAction from "./CodeStepAction.mdx";
@@ -48,10 +49,10 @@ function Step({
className?: string;
}) {
return (
<div
<Card
className={clsx(
className,
"rounded-lg overflow-hidden shadow-sm flex flex-col gap-6 border",
"overflow-hidden flex flex-col gap-6",
"pt-4 sm:pt-6",
"col-span-2 lg:col-span-3",
)}
@@ -70,7 +71,7 @@ function Step({
<p className="max-w-md">{description}</p>
</div>
<div className="flex-1 pl-4 sm:pl-12">{children}</div>
</div>
</Card>
);
}

View File

@@ -1,4 +1,5 @@
import { LabelledFeatureIcon } from "gcmp-design-system/src/app/components/molecules/LabelledFeatureIcon";
import { FeatureCard } from "gcmp-design-system/src/app/components/molecules/FeatureCard";
import { GappedGrid } from "gcmp-design-system/src/app/components/molecules/GappedGrid";
import { SectionHeader } from "gcmp-design-system/src/app/components/molecules/SectionHeader";
import {
GaugeIcon,
@@ -64,16 +65,16 @@ export function LocalFirstFeaturesSection() {
</>
}
/>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-4 lg:gap-8">
<GappedGrid cols={4}>
{features.map(({ title, icon: Icon, description }) => (
<LabelledFeatureIcon
<FeatureCard
label={title}
icon={Icon}
explanation={description}
key={title}
></LabelledFeatureIcon>
></FeatureCard>
))}
</div>
</GappedGrid>
</div>
);
}