Skip to content
Open
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