This commit is contained in:
DCCONSTRUCTIONS
2026-04-18 18:39:25 +03:00
commit 3ba092b60c
4944 changed files with 497564 additions and 0 deletions
@@ -0,0 +1,154 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Badge } from "./badge";
const meta = {
title: "Components/Badge",
component: Badge,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
args: {
children: "Badge",
},
} satisfies Meta<typeof Badge>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
export const Neutral: Story = {
args: {
variant: "neutral",
children: "Neutral Badge",
},
};
export const Brand: Story = {
args: {
variant: "brand",
children: "Brand Badge",
},
};
export const Warning: Story = {
args: {
variant: "warning",
children: "Warning Badge",
},
};
export const Success: Story = {
args: {
variant: "success",
children: "Success Badge",
},
};
export const Danger: Story = {
args: {
variant: "danger",
children: "Danger Badge",
},
};
export const Small: Story = {
args: {
size: "sm",
children: "Small Badge",
},
};
export const Base: Story = {
args: {
size: "base",
children: "Base Badge",
},
};
export const Large: Story = {
args: {
size: "lg",
children: "Large Badge",
},
};
export const WithPrependIcon: Story = {
args: {
prependIcon: (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12 5v14m-7-7h14" />
</svg>
),
children: "With Prepend Icon",
},
};
export const WithAppendIcon: Story = {
args: {
appendIcon: (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 5l7 7-7 7" />
</svg>
),
children: "With Append Icon",
},
};
export const AllVariants: Story = {
render() {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-16 font-semibold">Primary Variants</h3>
<div className="flex flex-wrap gap-2">
<Badge variant="neutral">Neutral</Badge>
<Badge variant="brand">Brand</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="danger">Danger</Badge>
</div>
</div>
</div>
);
},
};
export const AllSizes: Story = {
render() {
return (
<div className="space-y-4">
<div className="flex items-center gap-2">
<Badge size="sm">Small</Badge>
<Badge size="base">Base</Badge>
<Badge size="lg">Large</Badge>
</div>
</div>
);
},
};
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import * as React from "react";
import { cn } from "../utils";
import type { BadgeProps } from "./helper";
import { getBadgeIconStyling, badgeVariants } from "./helper";
const Badge = React.forwardRef(function Badge(props: BadgeProps, ref: React.ForwardedRef<HTMLSpanElement>) {
const { variant = "neutral", size = "base", prependIcon = null, appendIcon = null, children, ...rest } = props;
const badgeIconStyle = getBadgeIconStyling(size ?? "base");
return (
<span ref={ref} className={cn(badgeVariants({ variant, size }))} {...rest}>
{prependIcon && React.cloneElement(prependIcon, { className: cn("shrink-0", badgeIconStyle), strokeWidth: 2 })}
{children}
{appendIcon && React.cloneElement(appendIcon, { className: cn("shrink-0", badgeIconStyle), strokeWidth: 2 })}
</span>
);
});
Badge.displayName = "plane-ui-badge";
export { Badge };
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
export const badgeVariants = cva("inline-flex items-center justify-center gap-1 whitespace-nowrap transition-colors", {
variants: {
variant: {
neutral: "bg-layer-3 text-tertiary",
brand: "bg-accent-subtle-hover text-accent-primary",
warning: "bg-warning-subtle text-warning-primary",
success: "bg-success-subtle-1 text-success-primary",
danger: "bg-danger-subtle text-danger-primary",
},
size: {
sm: "h-4 rounded-sm px-1 text-caption-sm-medium",
base: "h-5 rounded-md px-1.5 text-caption-sm-medium",
lg: "h-6 rounded-md px-2 text-caption-md-medium",
},
},
defaultVariants: {
variant: "neutral",
size: "base",
},
});
export type BadgeProps = Omit<React.HTMLAttributes<HTMLSpanElement>, "className"> &
VariantProps<typeof badgeVariants> & {
appendIcon?: React.ReactElement;
prependIcon?: React.ReactElement;
};
export type TBadgeVariant = NonNullable<BadgeProps["variant"]>;
export type TBadgeSize = NonNullable<BadgeProps["size"]>;
const badgeIconStyling: Record<TBadgeSize, string> = {
sm: "size-3.5",
base: "size-3.5",
lg: "size-4",
};
export function getBadgeIconStyling(size: TBadgeSize): string {
return badgeIconStyling[size];
}
export function getBadgeStyling(variant: TBadgeVariant, size: TBadgeSize): string {
return badgeVariants({ variant, size });
}
@@ -0,0 +1,9 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
export { Badge } from "./badge";
export { getBadgeStyling } from "./helper";
export type { BadgeProps, TBadgeVariant, TBadgeSize } from "./helper";