Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
58 changes: 58 additions & 0 deletions src/components/Common/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from "react";
import clsx from "clsx";
import { Icon } from "./Icon";
import { IconName } from "@site/src/typescript/iconName";

export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
children: React.ReactNode;
className?: string;
variant?: "default" | "secondary" | "outline" | "success" | "warning" | "destructive";
size?: "sm" | "md";
iconName?: IconName;
iconPosition?: "left" | "right";
}

const variantClasses: Record<NonNullable<BadgeProps["variant"]>, string> = {
default: "bg-primary-light/80 backdrop-blur-xs !text-white rounded border border-primary/10",
secondary: "bg-gray-200/70 backdrop-blur-xs text-black dark:bg-secondary/70 dark:text-black rounded border border-gray-300/10 dark:border-secondary/10",
outline: "bg-stone-100/30 backdrop-blur-xs text-black rounded border border-black/70",
success: "bg-green-300/80 backdrop-blur-xs text-green-950 rounded border border-green-400/10",
warning: "bg-orange-300/80 backdrop-blur-xs text-orange-950 rounded border border-orange-400/10",
destructive: "bg-red-300/80 bacdrop-blur-xs text-red-950 rounded border border-red-400/10",
}

const sizeClasses: Record<NonNullable<BadgeProps["size"]>, string> = {
sm: "text-[11px] leading-4 h-5 px-2",
md: "text-xs leading-5 h-6 px-2.5",
};

export default function Badge({
children,
className = "",
variant = "secondary",
size = "sm",
iconName,
iconPosition = "left",
...props
}: BadgeProps) {
const baseClasses = clsx(
"inline-flex items-center gap-1 select-none",
"font-medium",
"rounded-full",
variantClasses[variant],
sizeClasses[size],
className,
);

const iconElement = iconName ? <Icon icon={iconName} size="xs" className="shrink-0" /> : null;

return (
<span className={baseClasses} {...props}>
{iconElement && iconPosition === "left" && iconElement}
<span>{children}</span>
{iconElement && iconPosition === "right" && iconElement}
</span>
);
}


21 changes: 16 additions & 5 deletions src/components/Common/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import * as React from "react";
import Link from "@docusaurus/Link";
import clsx from "clsx";
import { IconName } from "@site/src/typescript/iconName";
import { Icon } from "./Icon";
import isInternalUrl from "@docusaurus/isInternalUrl";

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children: React.ReactNode;
url?: string;
className?: string;
variant?: "default" | "outline" | "ghost" | "destructive";
variant?: "default" | "outline" | "ghost" | "destructive" | "secondary";
size?: "sm" | "md" | "lg";
iconName?: IconName;
}

const variantClasses: Record<NonNullable<ButtonProps["variant"]>, string> = {
default: "bg-primary !text-white dark:!text-black hover:bg-primary-darker",
secondary: "bg-gray-300 hover:bg-gray-400 dark:bg-secondary !text-black dark:hover:bg-secondary-darker",
outline:
"border !text-black border-black/25 !text-foreground hover:bg-black/5 dark:!text-white dark:border-white/25 dark:hover:bg-white/5",
ghost: "hover:bg-muted !text-foreground",
Expand All @@ -29,8 +34,9 @@ export default function Button({
children,
url,
className = "",
variant = "default",
variant = "secondary",
size = "md",
iconName,
...props
}: ButtonProps) {
const baseClasses = clsx(
Expand All @@ -43,16 +49,21 @@ export default function Button({
);

if (url) {
const external = !isInternalUrl(url);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const external = !isInternalUrl(url);
const isExternal = !isInternalUrl(url);

return (
<Link to={url} className={baseClasses}>
{children}
<Link
{...(external ? { href: url } : { to: url })}
className={baseClasses}
>
{children} {iconName && <Icon icon={iconName} />}
{external && <Icon icon="newtab" className="ml-2" size="xs"/>}
</Link>
);
}

return (
<button className={baseClasses} {...props}>
{children}
{children} {iconName && <Icon icon={iconName} />}
</button>
);
}
34 changes: 27 additions & 7 deletions src/components/Common/CardWithImage.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React, { ReactNode } from "react";
import Heading from "@theme/Heading";
import Button from "@site/src/components/Common/Button";
import { Icon } from "@site/src/components/Common/Icon";
import { IconName } from "@site/src/typescript/iconName";
import Badge from "@site/src/components/Common/Badge";
import isInternalUrl from "@docusaurus/isInternalUrl";

export interface CardWithImageProps {
title: string;
description: ReactNode;
imgSrc: string;
imgAlt?: string;
url?: string;
buttonVariant?: "default" | "outline" | "ghost" | "destructive" | "secondary";
ctaLabel?: string;
iconName?: IconName;
imgIcon?: IconName;
}

export default function CardWithImage({
Expand All @@ -17,23 +24,36 @@ export default function CardWithImage({
imgSrc,
imgAlt = "",
url,
buttonVariant = "secondary",
ctaLabel = "Read now",
iconName,
imgIcon,
}: CardWithImageProps) {
const hasImage = Boolean(imgSrc);
return (
<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">
<div className="flex items-center justify-center rounded-xl bg-black/40 mb-4 overflow-hidden">
<img
src={imgSrc}
alt={imgAlt}
className="pointer-events-none object-cover transition-transform origin-bottom duration-500 group-hover:scale-105 group-hover:translate-y-1"
/>
<div className={`flex items-center justify-center rounded-xl mb-4 overflow-hidden relative h-[132.96px] ${hasImage ? "bg-black/40" : "bg-gradient-to-b from-[#204879] to-[#0F1425] to-[70%]"}`}>
{hasImage ? (
<img
src={imgSrc}
alt={imgAlt}
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"
/>
) : (
<Icon icon={imgIcon ?? "default"} size="xl" className="filter brightness-0 invert" />
)}
{url && !isInternalUrl(url) && (
<Badge className="absolute top-2 right-2" variant="default" size="sm">
External
</Badge>
)}
</div>
<Heading as="h4" className="!mb-2">
{title}
</Heading>
<p className="!mb-3 text-sm">{description}</p>
{url && (
<Button variant="default" url={url} className="mt-auto">
<Button variant={buttonVariant} url={url} className="mt-auto">
{ctaLabel}
</Button>
)}
Expand Down
56 changes: 56 additions & 0 deletions src/components/Common/CardWithImageHorizontal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { ReactNode } from "react";
import Heading from "@theme/Heading";
import Button from "@site/src/components/Common/Button";
import { IconName } from "@site/src/typescript/iconName";
import Badge from "@site/src/components/Common/Badge";
import isInternalUrl from "@docusaurus/isInternalUrl";

export interface CardWithImageHorizontalProps {
title: string;
description: ReactNode;
imgSrc: string;
imgAlt?: string;
url?: string;
buttonVariant?: "default" | "outline" | "ghost" | "destructive" | "secondary";
ctaLabel?: string;
iconName?: IconName;
}

export default function CardWithImageHorizontal({
title,
description,
imgSrc,
imgAlt = "",
url,
buttonVariant = "secondary",
ctaLabel = "Read now",
iconName,
}: CardWithImageHorizontalProps) {
return (
<div className="card group flex !flex-row items-center gap-4 overflow-hidden rounded-2xl border border-black/10 dark:border-white/10 bg-muted/40 p-4 transition-colors">
<div className="basis-1/3 flex-shrink-0 overflow-hidden rounded-xl relative flex items-center">
<img
src={imgSrc}
alt={imgAlt}
className="pointer-events-none w-full h-auto object-contain transition-transform origin-bottom duration-500 group-hover:scale-105"
/>
{url && !isInternalUrl(url) && (
<Badge className="absolute top-2 right-2" variant="default" size="sm">
External
</Badge>
)}
</div>
<div className="flex flex-col flex-1 min-w-0 justify-center items-start gap-1">
<Heading as="h4" className="!mb-1">
{title}
</Heading>
<p className="!mb-3 text-sm">{description}</p>
{url && (
<Button variant={buttonVariant} size="sm" url={url} className="self-start">
{ctaLabel}
</Button>
)}
</div>
</div>
);
}
3 changes: 2 additions & 1 deletion src/components/Homepage/UseCases/UseCaseItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function UseCaseItem(props: CardWithImageProps) {
imgSrc={imgSrc}
imgAlt={imgAlt}
ctaLabel={ctaLabel}
/>
buttonVariant="default"
/>
);
}
39 changes: 39 additions & 0 deletions src/components/OneColGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from "react";
import clsx from "clsx";

export interface OneColGridProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
className?: string;
gap?: "sm" | "md" | "lg";
equalHeight?: boolean;
}

const gapClasses: Record<NonNullable<OneColGridProps["gap"]>, string> = {
sm: "gap-4",
md: "gap-6",
lg: "gap-8",
};

export default function OneColGrid({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make one component with colCount props instead of creating new component for each scenario?

children,
className = "",
gap = "sm",
equalHeight = false,
...props
}: OneColGridProps) {
return (
<div
className={clsx(
"grid grid-cols-1",
gapClasses[gap],
equalHeight && "[&>*]:h-full",
className,
)}
{...props}
>
{children}
</div>
);
}


37 changes: 37 additions & 0 deletions src/components/ThreeColGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from "react";
import clsx from "clsx";

export interface ThreeColGridProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
className?: string;
gap?: "sm" | "md" | "lg";
equalHeight?: boolean;
}

const gapClasses: Record<NonNullable<ThreeColGridProps["gap"]>, string> = {
sm: "gap-4",
md: "gap-6",
lg: "gap-8",
};

export default function ThreeColGrid({
children,
className = "",
gap = "sm",
equalHeight = false,
...props
}: ThreeColGridProps) {
return (
<div
className={clsx(
"grid [grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))]",
gapClasses[gap],
equalHeight && "[&>*]:h-full",
className,
)}
{...props}
>
{children}
</div>
);
}
39 changes: 39 additions & 0 deletions src/components/TwoColGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as React from "react";
import clsx from "clsx";

export interface TwoColGridProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
className?: string;
gap?: "sm" | "md" | "lg";
equalHeight?: boolean;
}

const gapClasses: Record<NonNullable<TwoColGridProps["gap"]>, string> = {
sm: "gap-4",
md: "gap-6",
lg: "gap-8",
};

export default function TwoColGrid({
children,
className = "",
gap = "sm",
equalHeight = false,
...props
}: TwoColGridProps) {
return (
<div
className={clsx(
"grid grid-cols-1 sm:grid-cols-2",
gapClasses[gap],
equalHeight && "[&>*]:h-full",
className,
)}
{...props}
>
{children}
</div>
);
}


21 changes: 21 additions & 0 deletions src/components/VersionConditional.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ReactNode } from "react";
import { useActiveDocContext } from "@docusaurus/plugin-content-docs/client";

interface VersionConditionalProps {
minimumVersion: string;
children: ReactNode;
}

export default function VersionConditional({
minimumVersion,
children,
}: VersionConditionalProps) {
const pluginId = "default";
const { activeVersion } = useActiveDocContext(pluginId);

if (minimumVersion > activeVersion.label) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are comparing string values, not number. It can be very tricky
e.g. "7.0">"7" == true

Use number values to compare.

Also it looks like the naming or condition is wrong. When minimumVersion is greater than activeVersion we do not render children?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kalczur please verify the code, but it appears to be working just fine
image

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In these scenarios yes, but check e.g.
"10.1" > "9.9"

JavaScript compares the string sign by sign

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping me if needed

Copy link
Contributor

@mateuszbartosik mateuszbartosik Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kalczur are we talking about the updated code? It appears to be working fine.
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sory, I looked at the old code, I will make a review of a new one

return null;
}

return <>{children}</>;
}
Loading
Loading