Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/components/common/CompactSectionSubtitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { ReactNode } from 'react';
import { cn } from '@/lib/utils';

interface CompactSectionSubtitleProps {
children: ReactNode;
className?: string;
}

const CompactSectionSubtitle: React.FC<CompactSectionSubtitleProps> = ({
children,
className,
}) => {
return (
<p
className={cn(
'mt-2 max-w-2xl text-sm leading-6 text-white/62 md:text-[0.95rem]',
className
)}
>
{children}
</p>
);
};

export default CompactSectionSubtitle;
11 changes: 11 additions & 0 deletions src/components/common/CreatorCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import CreatorInitialsAvatar from '@/components/common/CreatorInitialsAvatar';
import WalletConnectCalloutBanner from '@/components/common/WalletConnectCalloutBanner';
import CreatorSocialLinksList from '@/components/common/CreatorSocialLinksList';
import TransactionStatusIcon from '@/components/common/TransactionStatusIcon';
import MiniStatChip from '@/components/common/MiniStatChip';
import CreatorListRowDivider from '@/components/common/CreatorListRowDivider';

interface CreatorCardProps {
creator: Course;
Expand Down Expand Up @@ -92,6 +94,15 @@ const CreatorCard: React.FC<CreatorCardProps> = ({ creator, className }) => {
<p className="font-jakarta text-sm text-white/50">
@{creator.instructorId || 'creator'}
</p>
<div className="mt-3 flex flex-wrap gap-2">
<MiniStatChip label="Price" value={`${creator.price} ETH`} />
<MiniStatChip
label="Category"
value={creator.category || 'General'}
/>
<MiniStatChip label="Level" value={creator.level || 'Open'} />
</div>
<CreatorListRowDivider className="my-4" />
<div className="mt-3 space-y-1.5">
<CardMetaRow
label={
Expand Down
21 changes: 21 additions & 0 deletions src/components/common/CreatorListRowDivider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { cn } from '@/lib/utils';

interface CreatorListRowDividerProps {
className?: string;
}

const CreatorListRowDivider: React.FC<CreatorListRowDividerProps> = ({
className,
}) => {
return (
<div
className={cn(
'h-px w-full bg-gradient-to-r from-transparent via-white/10 to-transparent',
className
)}
aria-hidden="true"
/>
);
};

export default CreatorListRowDivider;
42 changes: 42 additions & 0 deletions src/components/common/CreatorProfileInfoGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { ReactNode } from 'react';
import { cn } from '@/lib/utils';

interface CreatorProfileInfoItem {
label: string;
value: ReactNode;
}

interface CreatorProfileInfoGridProps {
items: CreatorProfileInfoItem[];
className?: string;
}

const CreatorProfileInfoGrid: React.FC<CreatorProfileInfoGridProps> = ({
items,
className,
}) => {
return (
<div
className={cn(
'grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-4',
className
)}
>
{items.map(item => (
<div
key={item.label}
className="rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 backdrop-blur-sm"
>
<p className="text-[0.68rem] font-semibold uppercase tracking-[0.2em] text-white/42">
{item.label}
</p>
<div className="mt-2 font-jakarta text-sm font-semibold text-white md:text-[0.95rem]">
{item.value}
</div>
</div>
))}
</div>
);
};

export default CreatorProfileInfoGrid;
31 changes: 31 additions & 0 deletions src/components/common/MiniStatChip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { cn } from '@/lib/utils';

interface MiniStatChipProps {
label: string;
value: string;
className?: string;
}

const MiniStatChip: React.FC<MiniStatChipProps> = ({
label,
value,
className,
}) => {
return (
<div
className={cn(
'inline-flex min-w-0 items-center gap-2 rounded-full border border-white/10 bg-white/[0.06] px-2.5 py-1 text-[0.65rem] font-medium text-white/80 backdrop-blur-sm',
className
)}
>
<span className="shrink-0 uppercase tracking-[0.18em] text-white/42">
{label}
</span>
<span className="truncate font-jakarta text-xs font-semibold text-white">
{value}
</span>
</div>
);
};

export default MiniStatChip;
80 changes: 39 additions & 41 deletions src/components/common/SectionHeading.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,49 @@
import { cn } from '@/lib/utils';
import CompactSectionSubtitle from '@/components/common/CompactSectionSubtitle';

interface SectionHeadingProps {
title: string;
supportingText?: string;
eyebrow?: string;
className?: string;
titleClassName?: string;
supportingTextClassName?: string;
as?: 'h1' | 'h2' | 'h3' | 'p';
title: string;
supportingText?: string;
eyebrow?: string;
className?: string;
titleClassName?: string;
supportingTextClassName?: string;
as?: 'h1' | 'h2' | 'h3' | 'p';
}

const SectionHeading: React.FC<SectionHeadingProps> = ({
title,
supportingText,
eyebrow,
className,
titleClassName,
supportingTextClassName,
as: HeadingTag = 'h2',
title,
supportingText,
eyebrow,
className,
titleClassName,
supportingTextClassName,
as: HeadingTag = 'h2',
}) => {
return (
<div className={cn('min-w-0', className)}>
{eyebrow ? (
<p className="text-[0.68rem] font-bold uppercase tracking-[0.28em] text-amber-300/85">
{eyebrow}
</p>
) : null}
<HeadingTag
className={cn(
'mt-2 font-grotesque text-xl font-bold tracking-tight text-white md:text-2xl',
titleClassName
)}
>
{title}
</HeadingTag>
{supportingText ? (
<p
className={cn(
'mt-2 text-sm text-white/62 md:text-base',
supportingTextClassName
)}
>
{supportingText}
</p>
) : null}
</div>
);
return (
<div className={cn('min-w-0', className)}>
{eyebrow ? (
<p className="text-[0.68rem] font-bold uppercase tracking-[0.28em] text-amber-300/85">
{eyebrow}
</p>
) : null}
<HeadingTag
className={cn(
'mt-2 font-grotesque text-xl font-bold tracking-tight text-white md:text-2xl',
titleClassName
)}
>
{title}
</HeadingTag>
{supportingText ? (
<CompactSectionSubtitle
className={cn('md:text-base', supportingTextClassName)}
>
{supportingText}
</CompactSectionSubtitle>
) : null}
</div>
);
};

export default SectionHeading;
33 changes: 33 additions & 0 deletions src/pages/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import SectionDivider from '@/components/common/SectionDivider';
import { Button } from '@/components/ui/button';
import { UnavailableAction } from '@/components/ui/unavailable-action';
import SectionHeading from '@/components/common/SectionHeading';
import CompactSectionSubtitle from '@/components/common/CompactSectionSubtitle';
import CreatorProfileInfoGrid from '@/components/common/CreatorProfileInfoGrid';
import MiniStatChip from '@/components/common/MiniStatChip';

const FEATURED_CREATOR_FACTS = [
{ label: 'Membership', value: 'Collectors Circle' },
{ label: 'Drop cadence', value: 'Weekly releases' },
{ label: 'Focus', value: 'Illustration and motion' },
{ label: 'Community', value: 'Private behind-the-scenes notes' },
];

// Fallback demo data in case API fails
const DEMO_CREATORS: Course[] = [
Expand Down Expand Up @@ -209,6 +219,29 @@ function LandingPage() {
</div>
)}
</section>

<SectionDivider title="Creator profile pattern" spacing="relaxed" />

<section className="grid gap-8 rounded-[2rem] border border-white/10 bg-white/[0.045] p-6 shadow-[0_24px_80px_-60px_rgba(8,17,31,0.95)] backdrop-blur-sm md:p-8 lg:grid-cols-[1.1fr_0.9fr] lg:items-start">
<div>
<SectionHeading
eyebrow="Profile spotlight"
title="A reusable profile facts layout for featured creators"
className="mb-4"
/>
<CompactSectionSubtitle className="max-w-xl">
Use the same subtitle pattern beneath headings, then drop
repeated creator facts into one responsive grid that stays
tidy on mobile and desktop.
</CompactSectionSubtitle>
<div className="mt-5 flex flex-wrap gap-2">
<MiniStatChip label="Status" value="Verified creator" />
<MiniStatChip label="Audience" value="12.4K collectors" />
<MiniStatChip label="Access" value="Member-first drops" />
</div>
</div>
<CreatorProfileInfoGrid items={FEATURED_CREATOR_FACTS} />
</section>
</div>
</main>
);
Expand Down
Loading