mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: add storybook and new badge component with stories
This commit is contained in:
3
frontend/.gitignore
vendored
3
frontend/.gitignore
vendored
@@ -22,3 +22,6 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
*storybook.log
|
||||||
|
storybook-static
|
||||||
|
|||||||
17
frontend/.storybook/decorators/RouterDecorator.tsx
Normal file
17
frontend/.storybook/decorators/RouterDecorator.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { Decorator } from "@storybook/react-vite";
|
||||||
|
import { createRootRoute, createRouter, RouterProvider } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
export const RouterDecorator: Decorator = (Story) => {
|
||||||
|
const rootRoute = createRootRoute({
|
||||||
|
component: Story
|
||||||
|
});
|
||||||
|
|
||||||
|
const routeTree = rootRoute;
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
routeTree
|
||||||
|
});
|
||||||
|
|
||||||
|
// @ts-expect-error just to make Links happy :)
|
||||||
|
return <RouterProvider router={router} />;
|
||||||
|
};
|
||||||
1
frontend/.storybook/decorators/index.ts
Normal file
1
frontend/.storybook/decorators/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./RouterDecorator";
|
||||||
14
frontend/.storybook/main.ts
Normal file
14
frontend/.storybook/main.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import type { StorybookConfig } from "@storybook/react-vite";
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
stories: [
|
||||||
|
"../src/components/v3/**/*.mdx",
|
||||||
|
"../src/components/v3/**/*.stories.@(js|jsx|mjs|ts|tsx)"
|
||||||
|
],
|
||||||
|
addons: ["@storybook/addon-docs", "@storybook/addon-a11y"],
|
||||||
|
framework: {
|
||||||
|
name: "@storybook/react-vite",
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
45
frontend/.storybook/preview.tsx
Normal file
45
frontend/.storybook/preview.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import type { Preview } from "@storybook/react-vite";
|
||||||
|
|
||||||
|
import { RouterDecorator } from "./decorators";
|
||||||
|
|
||||||
|
import "../src/index.css";
|
||||||
|
|
||||||
|
const preview: Preview = {
|
||||||
|
decorators: [
|
||||||
|
(Story) => {
|
||||||
|
const root = document.getElementsByTagName("html")[0];
|
||||||
|
|
||||||
|
root.setAttribute("class", "overflow-visible");
|
||||||
|
|
||||||
|
return <Story />;
|
||||||
|
},
|
||||||
|
RouterDecorator
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
controls: {
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /Date$/i
|
||||||
|
}
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
backgroundColor: "var(--background)"
|
||||||
|
},
|
||||||
|
a11y: {
|
||||||
|
test: "todo"
|
||||||
|
},
|
||||||
|
backgrounds: {
|
||||||
|
default: "dark",
|
||||||
|
options: {
|
||||||
|
dark: { name: "Dark", value: "var(--background)" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initialGlobals: {
|
||||||
|
backgrounds: {
|
||||||
|
value: "dark"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default preview;
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
|
||||||
|
import storybook from "eslint-plugin-storybook";
|
||||||
|
|
||||||
import js from "@eslint/js";
|
import js from "@eslint/js";
|
||||||
import globals from "globals";
|
import globals from "globals";
|
||||||
import reactHooks from "eslint-plugin-react-hooks";
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
@@ -133,5 +136,6 @@ export default tseslint.config(
|
|||||||
rules: Object.fromEntries(
|
rules: Object.fromEntries(
|
||||||
Object.keys(stylisticPlugin.configs["all-flat"].rules ?? {}).map((key) => [key, "off"])
|
Object.keys(stylisticPlugin.configs["all-flat"].rules ?? {}).map((key) => [key, "off"])
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
storybook.configs["flat/recommended"]
|
||||||
);
|
);
|
||||||
|
|||||||
2089
frontend/package-lock.json
generated
2089
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,9 @@
|
|||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint ./src",
|
"lint": "eslint ./src",
|
||||||
"lint:fix": "eslint --fix ./src",
|
"lint:fix": "eslint --fix ./src",
|
||||||
"type:check": "tsc --noEmit --project ./tsconfig.app.json"
|
"type:check": "tsc --noEmit --project ./tsconfig.app.json",
|
||||||
|
"storybook": "storybook dev -p 6006",
|
||||||
|
"build-storybook": "storybook build"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"sha.js": "2.4.12"
|
"sha.js": "2.4.12"
|
||||||
@@ -47,7 +49,9 @@
|
|||||||
"@radix-ui/react-popper": "^1.2.1",
|
"@radix-ui/react-popper": "^1.2.1",
|
||||||
"@radix-ui/react-progress": "^1.1.1",
|
"@radix-ui/react-progress": "^1.1.1",
|
||||||
"@radix-ui/react-radio-group": "^1.2.2",
|
"@radix-ui/react-radio-group": "^1.2.2",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.1.3",
|
"@radix-ui/react-select": "^2.1.3",
|
||||||
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
"@radix-ui/react-switch": "^1.1.2",
|
"@radix-ui/react-switch": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.2",
|
"@radix-ui/react-tabs": "^1.1.2",
|
||||||
"@radix-ui/react-toast": "^1.2.3",
|
"@radix-ui/react-toast": "^1.2.3",
|
||||||
@@ -64,6 +68,7 @@
|
|||||||
"argon2-browser": "^1.18.0",
|
"argon2-browser": "^1.18.0",
|
||||||
"axios": "^1.12.0",
|
"axios": "^1.12.0",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
"cva": "npm:class-variance-authority@^0.7.1",
|
"cva": "npm:class-variance-authority@^0.7.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"dompurify": "^3.2.4",
|
"dompurify": "^3.2.4",
|
||||||
@@ -76,6 +81,7 @@
|
|||||||
"jsrp": "^0.2.4",
|
"jsrp": "^0.2.4",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"lexical": "^0.29.0",
|
"lexical": "^0.29.0",
|
||||||
|
"lucide-react": "^0.544.0",
|
||||||
"ms": "^2.1.3",
|
"ms": "^2.1.3",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"picomatch": "^4.0.2",
|
"picomatch": "^4.0.2",
|
||||||
@@ -105,6 +111,9 @@
|
|||||||
"@eslint/eslintrc": "^3.2.0",
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
"@eslint/js": "^9.15.0",
|
"@eslint/js": "^9.15.0",
|
||||||
"@kesills/eslint-config-airbnb-typescript": "^20.0.0",
|
"@kesills/eslint-config-airbnb-typescript": "^20.0.0",
|
||||||
|
"@storybook/addon-a11y": "^9.1.9",
|
||||||
|
"@storybook/addon-docs": "^9.1.9",
|
||||||
|
"@storybook/react-vite": "^9.1.9",
|
||||||
"@stylistic/eslint-plugin": "^2.12.1",
|
"@stylistic/eslint-plugin": "^2.12.1",
|
||||||
"@tailwindcss/postcss": "^4.1.14",
|
"@tailwindcss/postcss": "^4.1.14",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
@@ -130,6 +139,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"eslint-plugin-react-refresh": "^0.4.14",
|
"eslint-plugin-react-refresh": "^0.4.14",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
|
"eslint-plugin-storybook": "^9.1.9",
|
||||||
"globals": "^15.12.0",
|
"globals": "^15.12.0",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"prettier": "3.4.2",
|
"prettier": "3.4.2",
|
||||||
|
|||||||
BIN
frontend/public/fonts/AllianceNo2-Regular.otf
Normal file
BIN
frontend/public/fonts/AllianceNo2-Regular.otf
Normal file
Binary file not shown.
BIN
frontend/public/images/logotransparent_trimmed.png
Normal file
BIN
frontend/public/images/logotransparent_trimmed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
1
frontend/public/lotties/infisical_loading_white.json
Normal file
1
frontend/public/lotties/infisical_loading_white.json
Normal file
File diff suppressed because one or more lines are too long
307
frontend/src/components/v3/generic/Badge/Badge.stories.tsx
Normal file
307
frontend/src/components/v3/generic/Badge/Badge.stories.tsx
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||||
|
import { Link } from "@tanstack/react-router";
|
||||||
|
import {
|
||||||
|
BanIcon,
|
||||||
|
BoxesIcon,
|
||||||
|
BoxIcon,
|
||||||
|
CheckIcon,
|
||||||
|
ChevronsUpDownIcon,
|
||||||
|
CircleXIcon,
|
||||||
|
ExternalLinkIcon,
|
||||||
|
GlobeIcon,
|
||||||
|
InfoIcon,
|
||||||
|
RadarIcon,
|
||||||
|
TriangleAlertIcon
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
import { Badge } from "./Badge";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badges act as an indicator that can optionally be made interactable.
|
||||||
|
* You can place text and icons inside a badge.
|
||||||
|
* Badges are often used for the indication of a status, state or scope.
|
||||||
|
*/
|
||||||
|
const meta = {
|
||||||
|
title: "Generic/Badge",
|
||||||
|
component: Badge,
|
||||||
|
parameters: {
|
||||||
|
layout: "centered"
|
||||||
|
},
|
||||||
|
tags: ["autodocs"],
|
||||||
|
argTypes: {
|
||||||
|
variant: {
|
||||||
|
control: "select",
|
||||||
|
options: ["neutral", "success", "info", "warning", "danger", "project", "org", "sub-org"]
|
||||||
|
},
|
||||||
|
isTruncatable: {
|
||||||
|
table: {
|
||||||
|
disable: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
asChild: {
|
||||||
|
table: {
|
||||||
|
disable: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: {
|
||||||
|
table: {
|
||||||
|
disable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
args: { children: "Badge", isTruncatable: false }
|
||||||
|
} satisfies Meta<typeof Badge>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
export const Neutral: Story = {
|
||||||
|
name: "Variant: Neutral",
|
||||||
|
args: {
|
||||||
|
variant: "neutral",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<BanIcon />
|
||||||
|
Disabled
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating neutral or disabled states."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Success: Story = {
|
||||||
|
name: "Variant: Success",
|
||||||
|
args: {
|
||||||
|
variant: "success",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<CheckIcon />
|
||||||
|
Success
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating successful or healthy states."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Info: Story = {
|
||||||
|
name: "Variant: Info",
|
||||||
|
args: {
|
||||||
|
variant: "info",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<InfoIcon />
|
||||||
|
Info
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story:
|
||||||
|
"Use this variant when indicating informational states or linking to external references."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Warning: Story = {
|
||||||
|
name: "Variant: Warning",
|
||||||
|
args: {
|
||||||
|
variant: "warning",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<TriangleAlertIcon />
|
||||||
|
Warning
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating activity or attention warranting states."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Danger: Story = {
|
||||||
|
name: "Variant: Danger",
|
||||||
|
args: {
|
||||||
|
variant: "danger",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<CircleXIcon />
|
||||||
|
Danger
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating destructive or error states."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Organization: Story = {
|
||||||
|
name: "Variant: Organization",
|
||||||
|
args: {
|
||||||
|
variant: "org",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<GlobeIcon />
|
||||||
|
Organization
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating organization scope or links."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SubOrganization: Story = {
|
||||||
|
name: "Variant: Sub-Organization",
|
||||||
|
args: {
|
||||||
|
variant: "sub-org",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<BoxesIcon />
|
||||||
|
Sub-Organization
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating sub-organization scope or links."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Project: Story = {
|
||||||
|
name: "Variant: Project",
|
||||||
|
args: {
|
||||||
|
variant: "project",
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<BoxIcon />
|
||||||
|
Project
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use this variant when indicating project scope or links."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AsExternalLink: Story = {
|
||||||
|
name: "Example: As External Link",
|
||||||
|
args: {
|
||||||
|
variant: "info",
|
||||||
|
asChild: true,
|
||||||
|
children: (
|
||||||
|
<a href="https://infisical.com/">
|
||||||
|
Link <ExternalLinkIcon />
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use the `asChild` prop with an `a` tag to use a badge as an external link."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AsRouterLink: Story = {
|
||||||
|
name: "Example: As Router Link",
|
||||||
|
args: {
|
||||||
|
variant: "project",
|
||||||
|
asChild: true,
|
||||||
|
children: (
|
||||||
|
<Link to=".">
|
||||||
|
<RadarIcon />
|
||||||
|
Secret Scanning
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story: "Use the `asChild` prop with a `Link` component to use a badge as an internal link."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AsButton: Story = {
|
||||||
|
name: "Example: As Button",
|
||||||
|
args: {
|
||||||
|
variant: "org",
|
||||||
|
asChild: true,
|
||||||
|
children: (
|
||||||
|
<button type="button" onClick={() => alert("button clicked")}>
|
||||||
|
<GlobeIcon />
|
||||||
|
Organization
|
||||||
|
<ChevronsUpDownIcon />
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story:
|
||||||
|
"Use the `asChild` prop with a `button` tag to use a badge as a button. Do not use a styled `Button` component."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IsTruncatable: Story = {
|
||||||
|
name: "Example: isTruncatable",
|
||||||
|
args: {
|
||||||
|
isTruncatable: true,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<GlobeIcon />
|
||||||
|
<span>Infisical Infrastructure</span>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
docs: {
|
||||||
|
description: {
|
||||||
|
story:
|
||||||
|
"Use the `isTruncatable` prop with a `span` tag wrapping the text content to support truncation."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
decorators: (Story) => (
|
||||||
|
<div className="flex w-32">
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
||||||
82
frontend/src/components/v3/generic/Badge/Badge.tsx
Normal file
82
frontend/src/components/v3/generic/Badge/Badge.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { forwardRef } from "react";
|
||||||
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
|
import { cva, type VariantProps } from "cva";
|
||||||
|
|
||||||
|
import { cn } from "@app/components/v3/utils";
|
||||||
|
|
||||||
|
const badgeVariants = cva(
|
||||||
|
[
|
||||||
|
"select-none items-center rounded-sm px-1.5 py-0.5 text-xs",
|
||||||
|
"gap-x-1 [a&,button&]:cursor-pointer inline-flex",
|
||||||
|
"[&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:stroke-[2.25] [&>svg]:size-3",
|
||||||
|
"transition duration-200 ease-in-out"
|
||||||
|
],
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
isTruncatable: {
|
||||||
|
true: "[&>span,&>p]:truncate min-w-0",
|
||||||
|
false: "w-fit shrink-0 whitespace-nowrap overflow-hidden"
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
neutral: [
|
||||||
|
"border-neutral/75 bg-neutral/30 text-neutral",
|
||||||
|
"[a&,button&]:hover:bg-neutral/40 [a&,button&]:hover:border-neutral"
|
||||||
|
],
|
||||||
|
success: [
|
||||||
|
"border-success/75 bg-success/30 text-success",
|
||||||
|
"[a&,button&]:hover:bg-success/40 [a&,button&]:hover:border-success"
|
||||||
|
],
|
||||||
|
info: [
|
||||||
|
"border-info/75 bg-info/30 text-info",
|
||||||
|
"[a&,button&]:hover:bg-info/40 [a&,button&]:hover:border-info"
|
||||||
|
],
|
||||||
|
warning: [
|
||||||
|
"border-warning/75 bg-warning/30 text-warning",
|
||||||
|
"[a&,button&]:hover:bg-warning/40 [a&,button&]:hover:border-warning"
|
||||||
|
],
|
||||||
|
danger: [
|
||||||
|
"border-danger/75 bg-danger/30 text-danger",
|
||||||
|
"[a&,button&]:hover:bg-danger/40 [a&,button&]:hover:border-danger"
|
||||||
|
],
|
||||||
|
project: [
|
||||||
|
"border-project/75 bg-project/30 text-project",
|
||||||
|
"[a&,button&]:hover:bg-project/40 [a&,button&]:hover:border-project"
|
||||||
|
],
|
||||||
|
org: [
|
||||||
|
"border-org/75 bg-org/30 text-org",
|
||||||
|
"[a&,button&]:hover:bg-org/40 [a&,button&]:hover:border-org"
|
||||||
|
],
|
||||||
|
"sub-org": [
|
||||||
|
"border-sub-org/75 bg-sub-org/30 text-sub-org",
|
||||||
|
"[a&,button&]:hover:bg-sub-org/40 [a&,button&]:hover:border-sub-org"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "success"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type TBadgeProps = VariantProps<typeof badgeVariants> &
|
||||||
|
React.ComponentProps<"span"> & {
|
||||||
|
asChild?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Badge = forwardRef<HTMLButtonElement | HTMLSpanElement | HTMLAnchorElement, TBadgeProps>(
|
||||||
|
({ className, variant, asChild = false, isTruncatable = false, ...props }, ref): JSX.Element => {
|
||||||
|
const Comp = asChild ? Slot : "span";
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
ref={ref}
|
||||||
|
data-slot="badge"
|
||||||
|
className={cn(badgeVariants({ variant, isTruncatable }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Badge.displayName = "Badge";
|
||||||
|
|
||||||
|
export { Badge, badgeVariants, type TBadgeProps };
|
||||||
1
frontend/src/components/v3/generic/Badge/index.ts
Normal file
1
frontend/src/components/v3/generic/Badge/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./Badge";
|
||||||
1
frontend/src/components/v3/generic/index.ts
Normal file
1
frontend/src/components/v3/generic/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./Badge";
|
||||||
0
frontend/src/components/v3/index.ts
Normal file
0
frontend/src/components/v3/index.ts
Normal file
6
frontend/src/components/v3/utils/index.ts
Normal file
6
frontend/src/components/v3/utils/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { type ClassValue, clsx } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
@@ -37,12 +37,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
/*legacy color schema */
|
|
||||||
/* Fonts */
|
/* Fonts */
|
||||||
--font-inter: "Inter", sans-serif;
|
--font-inter: "Inter", sans-serif;
|
||||||
|
--max-width-8xl: 88rem; /* 1408px */
|
||||||
|
|
||||||
|
/* Colors v2 */
|
||||||
|
--color-background: #19191c;
|
||||||
|
--color-foreground: white;
|
||||||
|
--color-success: #2ecc71;
|
||||||
|
--color-info: #34c2db;
|
||||||
|
--color-warning: #f1c40f;
|
||||||
|
--color-danger: #e74c3c;
|
||||||
|
--color-org: #30B3FF;
|
||||||
|
--color-sub-org: #96ff59;
|
||||||
|
--color-project: #e0ed34;
|
||||||
|
--color-neutral: #adaeb0;
|
||||||
|
|
||||||
|
/*legacy color schema */
|
||||||
--color-org-v1: #30B3FF;
|
--color-org-v1: #30B3FF;
|
||||||
--color-namespace-v1: #96ff59;
|
--color-namespace-v1: #96ff59;
|
||||||
--max-width-8xl: 88rem; /* 1408px */
|
|
||||||
/* Primary */
|
/* Primary */
|
||||||
--color-primary-50: #fffff5;
|
--color-primary-50: #fffff5;
|
||||||
--color-primary-100: #fcfce8;
|
--color-primary-100: #fcfce8;
|
||||||
|
|||||||
@@ -31,5 +31,7 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts",
|
"./src/**/*.ts",
|
||||||
"./src/**/*.tsx",
|
"./src/**/*.tsx",
|
||||||
|
"./.storybook/**/*.ts",
|
||||||
|
"./.storybook/**/*.tsx",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user