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
2 changes: 2 additions & 0 deletions src/app/matricole/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Metadata } from "next"
import { FAQsPage } from "@/components/matricole/faqs"
import { MatricoleGuides } from "@/components/matricole/guides"
import { MatricoleIntro } from "@/components/matricole/intro"

export const metadata: Metadata = {
Expand All @@ -11,6 +12,7 @@ export default function MatricolePage() {
return (
<main className="w-full">
<MatricoleIntro />
<MatricoleGuides />
<FAQsPage />
</main>
)
Expand Down
26 changes: 26 additions & 0 deletions src/components/card-group/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { cn } from "@/lib/utils"
import { GradientIcon } from "../gradient-icon"
import type { CardGroupProps } from "./types"

export function CardGroupHeader({
icon,
title,
description,
horizontal,
}: Pick<CardGroupProps, "icon" | "title" | "description" | "horizontal">) {
return (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3 sm:flex-col sm:items-start sm:gap-6">
{icon && <GradientIcon icon={icon} className="h-8 w-8 sm:h-14 sm:w-14" />}
<h3 className="typo-headline-small sm:typo-headline-medium bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent">
{title}
</h3>
</div>
{description && (
<p className={cn("typo-body-large w-full text-text-primary", horizontal ? "max-w-lg sm:w-47" : "max-w-lg")}>
{description}
</p>
)}
</div>
)
}
22 changes: 22 additions & 0 deletions src/components/card-group/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Glass } from "@/components/glass"
import { cn } from "@/lib/utils"
import { CardGroupHeader } from "./header"
import type { CardGroupProps } from "./types"

export function CardGroup({ icon, title, description, children, horizontal = false, className }: CardGroupProps) {
return (
<Glass className={cn("w-full rounded-rectangles border-white/50 bg-background-blur p-12", className)}>
{horizontal ? (
<div className="flex flex-col gap-12 lg:flex-row lg:items-center">
<CardGroupHeader icon={icon} title={title} description={description} horizontal />
<div className="flex-1">{children}</div>
</div>
) : (
<>
<CardGroupHeader icon={icon} title={title} description={description} />
<div className="mt-12">{children}</div>
</>
)}
</Glass>
)
}
11 changes: 11 additions & 0 deletions src/components/card-group/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { ReactNode } from "react"
import type { GradientIconType } from "../gradient-icon"

export type CardGroupProps = {
icon?: GradientIconType
title: string
description?: string
children: ReactNode
horizontal?: boolean
className?: string
}
14 changes: 14 additions & 0 deletions src/components/card-icon/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const ICON_SIZE_CLASSES: SizeClassMap = {
sm: "h-14 w-14",
md: "h-32 w-32",
lg: "h-44 w-44",
inline: "h-6 w-6",
}

export const CARD_PADDING_WITHOUT_DESCRIPTION: SizeClassMap = {
Expand All @@ -14,6 +15,7 @@ export const CARD_PADDING_WITHOUT_DESCRIPTION: SizeClassMap = {
sm: "px-8 py-4",
md: "p-8",
lg: "p-8",
inline: "p-6",
}

export const CARD_PADDING_WITH_DESCRIPTION: SizeClassMap = {
Expand All @@ -22,6 +24,7 @@ export const CARD_PADDING_WITH_DESCRIPTION: SizeClassMap = {
sm: "p-8",
md: "p-8",
lg: "p-8",
inline: "p-6",
}

export const CONTENT_GAP_CLASSES: SizeClassMap = {
Expand All @@ -30,6 +33,7 @@ export const CONTENT_GAP_CLASSES: SizeClassMap = {
sm: "gap-2",
md: "gap-6",
lg: "gap-6",
inline: "gap-4",
}

export const TITLE_SIZE_CLASSES: SizeClassMap = {
Expand All @@ -38,4 +42,14 @@ export const TITLE_SIZE_CLASSES: SizeClassMap = {
sm: "typo-headline-medium",
md: "typo-headline-medium",
lg: "typo-headline-medium",
inline: "typo-title-large",
}

export const INLINE_CONTAINER_SIZE_CLASSES: SizeClassMap = {
compact: "h-12 w-12",
xs: "h-10 w-10",
sm: "h-12 w-12",
md: "h-14 w-14",
lg: "h-16 w-16",
inline: "h-10 w-10",
}
89 changes: 46 additions & 43 deletions src/components/card-icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,18 @@ import { cn } from "@/lib/utils"
import { BasicCardMedia } from "./basic-card-media"
import { DescriptionCardMedia } from "./description-card-media"
import { CardHoverBackground } from "./hover-background"
import { InlineCardMedia } from "./inline-card-media"
import type { CardIconProps } from "./types"
import { getCardPaddingClasses, getContentGapClasses, getTitleSizeClasses } from "./utils"
import { getAlignmentClasses, getCardPaddingClasses, getContentGapClasses, getTitleSizeClasses } from "./utils"

export function CardIcon(props: CardIconProps) {
const { title, icon, size = "md", href, hoverEffect = false, align = "center", className } = props
const description = "description" in props ? props.description : undefined
const Root = href ? "a" : "div"
const isDescriptionCard = Boolean(description)
const isStartAligned = align === "start"
const isInlineAligned = align === "inline"
const isCompactDescriptionCard = isDescriptionCard && size === "compact"
const contentAlignmentClass = isDescriptionCard
? isStartAligned
? "items-start justify-start text-left"
: "justify-between"
: isStartAligned
? "items-start justify-center text-left"
: "items-center justify-center text-center"
const textAlignmentClass = isDescriptionCard
? isStartAligned
? "items-start gap-5 text-left"
: "gap-2 text-left"
: isStartAligned
? "items-start text-left"
: "items-center text-center"
const { contentClass, textClass, iconWrapClass } = getAlignmentClasses(align, isDescriptionCard)

return (
<Glass
Expand All @@ -44,39 +32,54 @@ export function CardIcon(props: CardIconProps) {
>
{hoverEffect && <CardHoverBackground />}

<div
className={cn("relative z-10 flex h-full flex-1 flex-col", getContentGapClasses(size), contentAlignmentClass)}
>
<div className={cn("flex", isStartAligned ? "justify-start" : "justify-center")}>
{isDescriptionCard ? (
<DescriptionCardMedia icon={icon} size={size} />
) : (
<BasicCardMedia icon={icon} size={size} />
)}
{isInlineAligned ? (
<div className="relative z-10 flex flex-col gap-2">
<div className="flex items-center gap-2">
<InlineCardMedia icon={icon} size={size} />
<h3
className={cn(
getTitleSizeClasses(size),
"bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent"
)}
>
{title}
</h3>
</div>
{description && <p className="typo-body-large text-left text-text-primary">{description}</p>}
</div>

<div className={cn("flex flex-col", textAlignmentClass)}>
<h3
className={cn(
getTitleSizeClasses(size),
"bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent",
isDescriptionCard || isStartAligned ? "text-left" : "text-center"
) : (
<div className={cn("relative z-10 flex h-full flex-1 flex-col", getContentGapClasses(size), contentClass)}>
<div className={cn("flex", iconWrapClass)}>
{isDescriptionCard ? (
<DescriptionCardMedia icon={icon} size={size} />
) : (
<BasicCardMedia icon={icon} size={size} />
)}
>
{title}
</h3>
{description && (
<p
</div>

<div className={cn("flex flex-col", textClass)}>
<h3
className={cn(
"text-left text-text-primary",
isCompactDescriptionCard ? "typo-body-large max-w-60" : "typo-body-medium max-w-sm"
getTitleSizeClasses(size),
"bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent",
isDescriptionCard || align === "start" ? "text-left" : "text-center"
)}
>
{description}
</p>
)}
{title}
</h3>
{description && (
<p
className={cn(
"text-left text-text-primary",
isCompactDescriptionCard ? "typo-body-large max-w-60" : "typo-body-medium max-w-sm"
)}
>
{description}
</p>
)}
</div>
</div>
</div>
)}
</Root>
</Glass>
)
Expand Down
17 changes: 17 additions & 0 deletions src/components/card-icon/inline-card-media.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { cn } from "@/lib/utils"
import type { GradientIconType } from "../gradient-icon"
import type { ResponsiveCardSize } from "./types"
import { getIconSizeClasses, getInlineContainerClasses } from "./utils"
Comment thread
BIA3IA marked this conversation as resolved.

export function InlineCardMedia({ icon: Icon, size }: { icon: GradientIconType; size: ResponsiveCardSize }) {
return (
<div
className={cn(
"flex shrink-0 items-center justify-center rounded-lg bg-blue-tertiary",
getInlineContainerClasses(size)
)}
>
<Icon className={cn(getIconSizeClasses("inline"), "text-text-primary")} />
</div>
)
}
4 changes: 2 additions & 2 deletions src/components/card-icon/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { GradientIconType } from "@/components/gradient-icon"

export type CardSize = "compact" | "xs" | "sm" | "md" | "lg"
export type CardSize = "compact" | "xs" | "sm" | "md" | "lg" | "inline"
export type CardBreakpoint = "base" | "sm" | "md" | "lg"
export type CardAlign = "center" | "start"
export type CardAlign = "center" | "start" | "inline"

export type SizeClassMap = Record<CardSize, string>

Expand Down
27 changes: 26 additions & 1 deletion src/components/card-icon/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import {
CARD_PADDING_WITHOUT_DESCRIPTION,
CONTENT_GAP_CLASSES,
ICON_SIZE_CLASSES,
INLINE_CONTAINER_SIZE_CLASSES,
TITLE_SIZE_CLASSES,
} from "./classes"

import type { CardBreakpoint, ResponsiveCardSize, SizeClassMap } from "./types"
import type { CardAlign, CardBreakpoint, ResponsiveCardSize, SizeClassMap } from "./types"

const BREAKPOINTS: CardBreakpoint[] = ["base", "sm", "md", "lg"]

Expand Down Expand Up @@ -61,3 +62,27 @@ export function getContentGapClasses(size: ResponsiveCardSize) {
export function getTitleSizeClasses(size: ResponsiveCardSize) {
return resolveResponsiveClasses(size, TITLE_SIZE_CLASSES)
}

export function getInlineContainerClasses(size: ResponsiveCardSize) {
return resolveResponsiveClasses(size, INLINE_CONTAINER_SIZE_CLASSES)
}

export function getAlignmentClasses(align: CardAlign, hasDescription: boolean) {
return {
center: {
contentClass: hasDescription ? "justify-between" : "items-center justify-center text-center",
textClass: hasDescription ? "gap-2 text-left" : "items-center text-center",
iconWrapClass: "justify-center",
},
start: {
contentClass: hasDescription ? "items-start justify-start text-left" : "items-start justify-center text-left",
textClass: hasDescription ? "items-start gap-5 text-left" : "items-start text-left",
iconWrapClass: "justify-start",
},
inline: {
contentClass: "",
textClass: "",
iconWrapClass: "",
},
}[align]
}
Loading
Loading