Skip to content

Commit 7efa5bb

Browse files
authored
Merge pull request #2125 from monikaksiaz/RDoc-3494
RDoc-3494 Feature-specific page
2 parents cf3135b + 24d9b86 commit 7efa5bb

File tree

8 files changed

+310
-15
lines changed

8 files changed

+310
-15
lines changed

src/components/ColGrid.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as React from "react";
2+
import clsx from "clsx";
3+
4+
export type GridColCount = 1 | 2 | 3;
5+
6+
export interface ColGridProps extends React.HTMLAttributes<HTMLDivElement> {
7+
children: React.ReactNode;
8+
className?: string;
9+
colCount: GridColCount;
10+
}
11+
12+
function getGridColsClass(colCount: GridColCount): string {
13+
if (colCount === 1) {
14+
return "grid grid-cols-1";
15+
}
16+
if (colCount === 2) {
17+
return "grid grid-cols-1 sm:grid-cols-2";
18+
}
19+
if (colCount === 3) {
20+
return "grid grid-cols-1 xl:grid-cols-3";
21+
}
22+
return "";
23+
}
24+
25+
export default function ColGrid({
26+
children,
27+
className = "",
28+
colCount = 1,
29+
...props
30+
}: ColGridProps) {
31+
return (
32+
<div
33+
className={clsx(getGridColsClass(colCount), "gap-4", className)}
34+
{...props}
35+
>
36+
{children}
37+
</div>
38+
);
39+
}

src/components/Common/Badge.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as React from "react";
2+
import clsx from "clsx";
3+
import { Icon } from "./Icon";
4+
import { IconName } from "@site/src/typescript/iconName";
5+
6+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
7+
children: React.ReactNode;
8+
className?: string;
9+
variant?: "default" | "secondary" | "outline" | "success" | "warning" | "destructive";
10+
size?: "sm" | "md";
11+
iconName?: IconName;
12+
iconPosition?: "left" | "right";
13+
}
14+
15+
const variantClasses: Record<NonNullable<BadgeProps["variant"]>, string> = {
16+
default: "bg-primary-light/80 backdrop-blur-xs text-white border border-primary/10 dark:text-black",
17+
secondary: "bg-gray-200/70 backdrop-blur-xs text-black dark:bg-secondary/70 dark:text-black border border-gray-300/10 dark:border-secondary/10",
18+
outline: "bg-stone-100/30 backdrop-blur-xs text-black border border-black/70",
19+
success: "bg-green-300/80 backdrop-blur-xs text-green-950 border border-green-400/10",
20+
warning: "bg-orange-300/80 backdrop-blur-xs text-orange-950 border border-orange-400/10",
21+
destructive: "bg-red-300/80 backdrop-blur-xs text-red-950 border border-red-400/10",
22+
}
23+
24+
const sizeClasses: Record<NonNullable<BadgeProps["size"]>, string> = {
25+
sm: "text-[11px] leading-4 h-5 px-2",
26+
md: "text-xs leading-5 h-6 px-2.5",
27+
};
28+
29+
export default function Badge({
30+
children,
31+
className = "",
32+
variant = "secondary",
33+
size = "sm",
34+
iconName,
35+
iconPosition = "left",
36+
...props
37+
}: BadgeProps) {
38+
const baseClasses = clsx(
39+
"inline-flex items-center gap-1 select-none",
40+
"font-medium",
41+
"rounded-full",
42+
variantClasses[variant],
43+
sizeClasses[size],
44+
className,
45+
);
46+
47+
const iconElement = iconName ? <Icon icon={iconName} size="xs" className="shrink-0" /> : null;
48+
49+
return (
50+
<span className={baseClasses} {...props}>
51+
{iconElement && iconPosition === "left" && iconElement}
52+
<span>{children}</span>
53+
{iconElement && iconPosition === "right" && iconElement}
54+
</span>
55+
);
56+
}
57+
58+

src/components/Common/Button.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
import * as React from "react";
22
import Link from "@docusaurus/Link";
33
import clsx from "clsx";
4+
import { IconName } from "@site/src/typescript/iconName";
5+
import { Icon } from "./Icon";
6+
import isInternalUrl from "@docusaurus/isInternalUrl";
7+
8+
export type ButtonVariant =
9+
| "default"
10+
| "outline"
11+
| "ghost"
12+
| "destructive"
13+
| "secondary";
14+
415

516
export interface ButtonProps
617
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
718
children: React.ReactNode;
819
url?: string;
920
className?: string;
10-
variant?: "default" | "outline" | "ghost" | "destructive";
21+
variant?: ButtonVariant;
1122
size?: "sm" | "md" | "lg";
23+
iconName?: IconName;
1224
}
1325

14-
const variantClasses: Record<NonNullable<ButtonProps["variant"]>, string> = {
26+
const variantClasses: Record<ButtonVariant, string> = {
1527
default: "bg-primary !text-white dark:!text-black hover:bg-primary-darker",
28+
secondary: "bg-gray-300 hover:bg-gray-400 dark:bg-secondary !text-black dark:hover:bg-secondary-darker",
1629
outline:
1730
"border !text-black border-black/25 !text-foreground hover:bg-black/5 dark:!text-white dark:border-white/25 dark:hover:bg-white/5",
1831
ghost: "hover:bg-muted !text-foreground",
@@ -29,8 +42,9 @@ export default function Button({
2942
children,
3043
url,
3144
className = "",
32-
variant = "default",
45+
variant = "secondary",
3346
size = "md",
47+
iconName,
3448
...props
3549
}: ButtonProps) {
3650
const baseClasses = clsx(
@@ -43,16 +57,21 @@ export default function Button({
4357
);
4458

4559
if (url) {
60+
const isExternal = !isInternalUrl(url);
4661
return (
47-
<Link to={url} className={baseClasses}>
48-
{children}
62+
<Link
63+
{...(isExternal ? { href: url } : { to: url })}
64+
className={baseClasses}
65+
>
66+
{children} {iconName && <Icon icon={iconName} />}
67+
{isExternal && <Icon icon="newtab" className="ml-2" size="xs"/>}
4968
</Link>
5069
);
5170
}
5271

5372
return (
5473
<button className={baseClasses} {...props}>
55-
{children}
74+
{children} {iconName && <Icon icon={iconName} />}
5675
</button>
5776
);
5877
}

src/components/Common/CardWithImage.tsx

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
import React, { ReactNode } from "react";
22
import Heading from "@theme/Heading";
3-
import Button from "@site/src/components/Common/Button";
3+
import Button, { type ButtonVariant } from "@site/src/components/Common/Button";
4+
import { Icon } from "@site/src/components/Common/Icon";
5+
import { IconName } from "@site/src/typescript/iconName";
6+
import Badge from "@site/src/components/Common/Badge";
7+
import isInternalUrl from "@docusaurus/isInternalUrl";
48

59
export interface CardWithImageProps {
610
title: string;
711
description: ReactNode;
812
imgSrc: string;
913
imgAlt?: string;
1014
url?: string;
15+
buttonVariant?: ButtonVariant;
1116
ctaLabel?: string;
17+
iconName?: IconName;
18+
imgIcon?: IconName;
1219
}
1320

1421
export default function CardWithImage({
@@ -17,23 +24,36 @@ export default function CardWithImage({
1724
imgSrc,
1825
imgAlt = "",
1926
url,
27+
buttonVariant = "secondary",
2028
ctaLabel = "Read now",
29+
iconName,
30+
imgIcon,
2131
}: CardWithImageProps) {
32+
const hasImage = Boolean(imgSrc);
2233
return (
2334
<div className="card group flex flex-col overflow-hidden rounded-2xl border border-black/10 dark:border-white/10 bg-muted/40 p-4 transition-colors">
24-
<div className="flex items-center justify-center rounded-xl bg-black/40 mb-4 overflow-hidden">
25-
<img
26-
src={imgSrc}
27-
alt={imgAlt}
28-
className="pointer-events-none object-cover transition-transform origin-bottom duration-500 group-hover:scale-105 group-hover:translate-y-1"
29-
/>
35+
<div className={`flex items-center justify-center rounded-xl mb-4 overflow-hidden relative aspect-[79/24] ${hasImage ? "bg-black/40" : "bg-gradient-to-b from-[#204879] to-[#0F1425] to-[70%]"}`}>
36+
{hasImage ? (
37+
<img
38+
src={imgSrc}
39+
alt={imgAlt}
40+
className="pointer-events-none w-full h-full object-cover object-center transition-transform origin-bottom duration-500 group-hover:scale-105 group-hover:translate-y-1"
41+
/>
42+
) : (
43+
<Icon icon={imgIcon ?? "default"} size="xl" className="filter brightness-0 invert" />
44+
)}
45+
{url && !isInternalUrl(url) && (
46+
<Badge className="absolute top-2 right-2" variant="default" size="sm">
47+
External
48+
</Badge>
49+
)}
3050
</div>
3151
<Heading as="h4" className="!mb-2">
3252
{title}
3353
</Heading>
3454
<p className="!mb-3 text-sm">{description}</p>
3555
{url && (
36-
<Button variant="default" url={url} className="mt-auto">
56+
<Button variant={buttonVariant} url={url} className="mt-auto">
3757
{ctaLabel}
3858
</Button>
3959
)}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React, { ReactNode } from "react";
2+
import Heading from "@theme/Heading";
3+
import Button, { type ButtonVariant } from "@site/src/components/Common/Button";
4+
import { IconName } from "@site/src/typescript/iconName";
5+
import Badge from "@site/src/components/Common/Badge";
6+
import isInternalUrl from "@docusaurus/isInternalUrl";
7+
8+
export interface CardWithImageHorizontalProps {
9+
title: string;
10+
description: ReactNode;
11+
imgSrc: string;
12+
imgAlt?: string;
13+
url?: string;
14+
buttonVariant?: ButtonVariant;
15+
ctaLabel?: string;
16+
iconName?: IconName;
17+
}
18+
19+
export default function CardWithImageHorizontal({
20+
title,
21+
description,
22+
imgSrc,
23+
imgAlt = "",
24+
url,
25+
buttonVariant = "secondary",
26+
ctaLabel = "Read now",
27+
}: CardWithImageHorizontalProps) {
28+
return (
29+
<div className="card group !grid grid-cols-1 xl:grid-cols-[minmax(10rem,_230px)_1fr] 2xl:grid-cols-[minmax(10rem,_270px)_1fr] items-center gap-4 overflow-hidden rounded-2xl border border-black/10 dark:border-white/10 bg-muted/40 p-4 transition-colors">
30+
<div className="aspect-[537/281] overflow-hidden rounded-xl relative flex items-center">
31+
<img
32+
src={imgSrc}
33+
alt={imgAlt}
34+
className="pointer-events-none w-full h-auto object-contain transition-transform origin-bottom duration-500 group-hover:scale-105"
35+
/>
36+
{url && !isInternalUrl(url) && (
37+
<Badge
38+
className="absolute top-2 right-2"
39+
variant="default"
40+
size="sm"
41+
>
42+
External
43+
</Badge>
44+
)}
45+
</div>
46+
<div className="flex flex-col min-w-0 justify-center gap-1">
47+
<Heading as="h4" className="!mb-1">
48+
{title}
49+
</Heading>
50+
<p className="!mb-3 text-sm">{description}</p>
51+
{url && (
52+
<Button variant={buttonVariant} url={url}>
53+
{ctaLabel}
54+
</Button>
55+
)}
56+
</div>
57+
</div>
58+
);
59+
}

src/components/Homepage/UseCases/UseCaseItem.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export default function UseCaseItem(props: CardWithImageProps) {
1212
imgSrc={imgSrc}
1313
imgAlt={imgAlt}
1414
ctaLabel={ctaLabel}
15-
/>
15+
buttonVariant="default"
16+
/>
1617
);
1718
}

src/css/custom.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
--color-primary-light: var(--ifm-color-primary-light);
104104
--color-primary-lighter: var(--ifm-color-primary-lighter);
105105
--color-primary-lightest: var(--ifm-color-primary-lightest);
106+
--color-secondary: var(--ifm-color-secondary);
107+
--color-secondary-darker: var(--ifm-color-secondary-darker);
106108
--color-ifm-background: var(--ifm-background-color);
107109
--color-ifm-background-surface: var(--ifm-background-surface-color);
108110
--color-ifm-menu: var(--ifm-menu-color);

0 commit comments

Comments
 (0)