mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 11:27:47 +00:00
feat(ui): added ui components for new dashboard
This commit is contained in:
@@ -53,7 +53,7 @@ const deriveArgonKey = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return derivedKey;
|
return derivedKey;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
||||||
@@ -173,6 +173,7 @@ type DecryptSymmetricProps = {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const decryptSymmetric = ({ ciphertext, iv, tag, key }: DecryptSymmetricProps): string => {
|
const decryptSymmetric = ({ ciphertext, iv, tag, key }: DecryptSymmetricProps): string => {
|
||||||
|
if (!ciphertext) return '';
|
||||||
let plaintext;
|
let plaintext;
|
||||||
try {
|
try {
|
||||||
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
|
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const buttonVariants = cva(
|
|||||||
star: 'text-bunker-200 bg-mineshaft-500'
|
star: 'text-bunker-200 bg-mineshaft-500'
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-mineshaft opacity-40 cursor-not-allowed',
|
true: 'bg-mineshaft text-white opacity-50 cursor-not-allowed',
|
||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
@@ -155,26 +155,26 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
className="absolute rounded-xl"
|
className="absolute rounded-xl"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'shrink-0 cursor-pointer transition-all',
|
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
|
||||||
loadingToggleClass,
|
loadingToggleClass,
|
||||||
leftIcon && 'ml-2',
|
leftIcon && 'ml-2',
|
||||||
size === 'xs' ? 'mr-1' : 'mr-3'
|
size === 'xs' ? 'mr-1' : 'mr-2'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{leftIcon}
|
{leftIcon}
|
||||||
</span>
|
</div>
|
||||||
<span className={twMerge('transition-all', loadingToggleClass)}>{children}</span>
|
<span className={twMerge('w-full transition-all', loadingToggleClass)}>{children}</span>
|
||||||
<span
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'shrink-0 cursor-pointer transition-all',
|
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
|
||||||
loadingToggleClass,
|
loadingToggleClass,
|
||||||
size === 'xs' ? 'ml-1' : 'ml-3'
|
size === 'xs' ? 'ml-1' : 'ml-2'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{rightIcon}
|
{rightIcon}
|
||||||
</span>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import { Drawer, DrawerContent, DrawerContentProps, DrawerTrigger } from './Drawer';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Drawer> = {
|
||||||
|
title: 'Components/Drawer',
|
||||||
|
component: Drawer,
|
||||||
|
tags: ['v2'],
|
||||||
|
argTypes: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof DrawerContent>;
|
||||||
|
|
||||||
|
const Template = (args: DrawerContentProps) => (
|
||||||
|
<Drawer>
|
||||||
|
<DrawerTrigger asChild>
|
||||||
|
<Button>Open</Button>
|
||||||
|
</DrawerTrigger>
|
||||||
|
<DrawerContent {...args}>Hello world</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const Basic: Story = {
|
||||||
|
render: (args) => <Template {...args} />,
|
||||||
|
args: {
|
||||||
|
title: 'Title',
|
||||||
|
subTitle: 'Something as subtitle',
|
||||||
|
footerContent: 'footer content'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { forwardRef, ReactNode } from 'react';
|
||||||
|
import { faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||||
|
import { cva, VariantProps } from 'cva';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
import { Card, CardBody, CardFooter, CardTitle } from '../Card';
|
||||||
|
import { IconButton } from '../IconButton';
|
||||||
|
|
||||||
|
export type DrawerContentProps = DialogPrimitive.DialogContentProps & {
|
||||||
|
title?: ReactNode;
|
||||||
|
subTitle?: ReactNode;
|
||||||
|
footerContent?: ReactNode;
|
||||||
|
onClose?: () => void;
|
||||||
|
} & VariantProps<typeof drawerContentVariation>;
|
||||||
|
|
||||||
|
const drawerContentVariation = cva(
|
||||||
|
'fixed ease-in-out duration-300 z-[90] border border-mineshaft-600 drop-shadow-2xl',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
direction: {
|
||||||
|
right: [
|
||||||
|
'right-0 top-0',
|
||||||
|
'h-full w-96',
|
||||||
|
'data-[state=open]:animate-drawerRightIn data-[state=closed]:animate-drawerRightOut'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
|
||||||
|
(
|
||||||
|
{ children, title, subTitle, className, footerContent, direction = 'right', onClose, ...props },
|
||||||
|
forwardedRef
|
||||||
|
) => (
|
||||||
|
<DialogPrimitive.Portal>
|
||||||
|
<DialogPrimitive.Overlay
|
||||||
|
className="fixed inset-0 z-[70] h-full w-full"
|
||||||
|
style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)' }}
|
||||||
|
/>
|
||||||
|
<DialogPrimitive.Content
|
||||||
|
{...props}
|
||||||
|
ref={forwardedRef}
|
||||||
|
className={twMerge(drawerContentVariation({ direction, className }))}
|
||||||
|
>
|
||||||
|
<Card isRounded={false} className="h-full w-full">
|
||||||
|
{title && (
|
||||||
|
<CardTitle subTitle={subTitle} className="px-4">
|
||||||
|
{title}
|
||||||
|
</CardTitle>
|
||||||
|
)}
|
||||||
|
<CardBody className="flex-grow overflow-y-auto overflow-x-hidden px-4">
|
||||||
|
{children}
|
||||||
|
</CardBody>
|
||||||
|
{footerContent && <CardFooter>{footerContent}</CardFooter>}{' '}
|
||||||
|
<DialogPrimitive.Close aria-label="Close" asChild onClick={onClose}>
|
||||||
|
<IconButton
|
||||||
|
variant="plain"
|
||||||
|
ariaLabel="close"
|
||||||
|
className="absolute top-4 right-6 rounded text-bunker-400 hover:text-bunker-50"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTimes} size="lg" className="cursor-pointer" />
|
||||||
|
</IconButton>
|
||||||
|
</DialogPrimitive.Close>
|
||||||
|
</Card>
|
||||||
|
</DialogPrimitive.Content>
|
||||||
|
</DialogPrimitive.Portal>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawerContent.displayName = 'ModalContent';
|
||||||
|
|
||||||
|
export type DrawerProps = Omit<DialogPrimitive.DialogProps, 'open'> & { isOpen?: boolean };
|
||||||
|
export const Drawer = ({ isOpen, ...props }: DrawerProps) => (
|
||||||
|
<DialogPrimitive.Root open={isOpen} {...props} />
|
||||||
|
);
|
||||||
|
|
||||||
|
export const DrawerTrigger = DialogPrimitive.Trigger;
|
||||||
|
export type DrawerTriggerProps = DialogPrimitive.DialogTriggerProps;
|
||||||
|
|
||||||
|
export const DrawerClose = DialogPrimitive.Close;
|
||||||
|
export type DrawerCloseProps = DialogPrimitive.DialogCloseProps;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { Drawer, DrawerClose,DrawerContent, DrawerTrigger } from './Drawer';
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import {
|
||||||
|
HoverCard,
|
||||||
|
HoverCardContent,
|
||||||
|
HoverCardContentProps,
|
||||||
|
HoverCardTrigger
|
||||||
|
} from './HoverCardv2';
|
||||||
|
|
||||||
|
const meta: Meta<typeof HoverCardContent> = {
|
||||||
|
title: 'Components/HoverCard',
|
||||||
|
component: HoverCard,
|
||||||
|
tags: ['v2']
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof HoverCardContent>;
|
||||||
|
|
||||||
|
const Template = (args: HoverCardContentProps) => (
|
||||||
|
<HoverCard>
|
||||||
|
<HoverCardTrigger>
|
||||||
|
<Button>Hello world</Button>
|
||||||
|
</HoverCardTrigger>
|
||||||
|
<HoverCardContent {...args} sideOffset={10}>
|
||||||
|
<div className="bg-mineshaft-600 p-4 text-gray-400">
|
||||||
|
<h1>This is hover card</h1>
|
||||||
|
</div>
|
||||||
|
</HoverCardContent>
|
||||||
|
</HoverCard>
|
||||||
|
);
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||||
|
export const Primary: Story = {
|
||||||
|
render: (args) => <Template {...args} />
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
export const HoverCardTrigger = HoverCardPrimitive.Trigger;
|
||||||
|
|
||||||
|
export const HoverCard = HoverCardPrimitive.Root;
|
||||||
|
|
||||||
|
export type HoverCardContentProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
} & HoverCardPrimitive.HoverCardContentProps;
|
||||||
|
|
||||||
|
export const HoverCardContent = ({ children, className, ...props }: HoverCardContentProps) => (
|
||||||
|
<HoverCardPrimitive.Portal>
|
||||||
|
<HoverCardPrimitive.Content
|
||||||
|
{...props}
|
||||||
|
className={twMerge(
|
||||||
|
'relative w-64 rounded-md bg-mineshaft-600 fill-mineshaft-600 p-4 pt-6 font-inter text-gray-200 shadow-md',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<HoverCardPrimitive.Arrow className="fill-inherit stroke-inherit" />
|
||||||
|
</HoverCardPrimitive.Content>
|
||||||
|
</HoverCardPrimitive.Portal>
|
||||||
|
);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { HoverCard,HoverCardContent, HoverCardTrigger } from './HoverCardv2';
|
||||||
@@ -29,7 +29,8 @@ const iconButtonVariants = cva(
|
|||||||
variant: {
|
variant: {
|
||||||
solid: '',
|
solid: '',
|
||||||
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
||||||
plain: ''
|
plain: '',
|
||||||
|
star: 'text-bunker-200 bg-mineshaft-500'
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-opacity-70 cursor-not-allowed',
|
true: 'bg-opacity-70 cursor-not-allowed',
|
||||||
@@ -40,13 +41,23 @@ const iconButtonVariants = cva(
|
|||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
xs: ['text-xs', 'py-2', 'px-2'],
|
xs: ['text-xs', 'py-1.5', 'px-2'],
|
||||||
sm: ['text-sm', 'py-3', 'px-3'],
|
sm: ['text-sm', 'py-3', 'px-3'],
|
||||||
md: ['text-md', 'py-4', 'px-4'],
|
md: ['text-md', 'py-4', 'px-4'],
|
||||||
lg: ['text-lg', 'py-6', 'px-6']
|
lg: ['text-lg', 'py-6', 'px-6']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
compoundVariants: [
|
compoundVariants: [
|
||||||
|
{
|
||||||
|
colorSchema: 'primary',
|
||||||
|
variant: 'star',
|
||||||
|
className: 'hover:bg-primary hover:text-black'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'danger',
|
||||||
|
variant: 'star',
|
||||||
|
className: 'hover:bg-red hover:text-white'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'primary',
|
colorSchema: 'primary',
|
||||||
variant: 'outline',
|
variant: 'outline',
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ type Props = {
|
|||||||
leftIcon?: ReactNode;
|
leftIcon?: ReactNode;
|
||||||
rightIcon?: ReactNode;
|
rightIcon?: ReactNode;
|
||||||
isDisabled?: boolean;
|
isDisabled?: boolean;
|
||||||
|
isReadOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputVariants = cva(
|
const inputVariants = cva(
|
||||||
@@ -78,6 +79,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||||||
rightIcon,
|
rightIcon,
|
||||||
variant = 'filled',
|
variant = 'filled',
|
||||||
size = 'md',
|
size = 'md',
|
||||||
|
isReadOnly,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
@@ -89,6 +91,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||||||
{...props}
|
{...props}
|
||||||
required={isRequired}
|
required={isRequired}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
readOnly={isReadOnly}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
leftIcon ? 'pl-10' : 'pl-2.5',
|
leftIcon ? 'pl-10' : 'pl-2.5',
|
||||||
|
|||||||
@@ -12,20 +12,24 @@ export type ModalContentProps = DialogPrimitive.DialogContentProps & {
|
|||||||
subTitle?: ReactNode;
|
subTitle?: ReactNode;
|
||||||
footerContent?: ReactNode;
|
footerContent?: ReactNode;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
|
overlayClassName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
||||||
({ children, title, subTitle, className, footerContent, onClose, ...props }, forwardedRef) => (
|
(
|
||||||
|
{ children, title, subTitle, className, overlayClassName, footerContent, onClose, ...props },
|
||||||
|
forwardedRef
|
||||||
|
) => (
|
||||||
<DialogPrimitive.Portal>
|
<DialogPrimitive.Portal>
|
||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
className="fixed inset-0 h-full w-full animate-fadeIn z-[70]"
|
className={twMerge('fixed inset-0 z-[70] h-full w-full animate-fadeIn', overlayClassName)}
|
||||||
style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)' }}
|
style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)' }}
|
||||||
/>
|
/>
|
||||||
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
||||||
<Card
|
<Card
|
||||||
isRounded
|
isRounded
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'fixed top-1/2 left-1/2 max-w-lg border border-mineshaft-600 -translate-y-2/4 -translate-x-2/4 animate-popIn drop-shadow-2xl z-[90]',
|
'fixed top-1/2 left-1/2 z-[90] max-w-lg -translate-y-2/4 -translate-x-2/4 animate-popIn border border-mineshaft-600 drop-shadow-2xl',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import { Popover, PopoverContent, PopoverContentProps, PopoverTrigger } from './Popoverv2';
|
||||||
|
|
||||||
|
const meta: Meta<typeof PopoverContent> = {
|
||||||
|
title: 'Components/Popover',
|
||||||
|
component: Popover,
|
||||||
|
tags: ['v2']
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof PopoverContent>;
|
||||||
|
|
||||||
|
const Template = (args: PopoverContentProps) => (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button>Hello world</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent {...args} side="bottom" sideOffset={10}>
|
||||||
|
<h1>This is popper</h1>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||||
|
export const Primary: Story = {
|
||||||
|
render: (args) => <Template {...args} />
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
import { IconButton } from '../IconButton';
|
||||||
|
|
||||||
|
export const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||||
|
|
||||||
|
export const Popover = PopoverPrimitive.Root;
|
||||||
|
|
||||||
|
export type PopoverContentProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
hideCloseBtn?: boolean;
|
||||||
|
} & PopoverPrimitive.PopperContentProps;
|
||||||
|
|
||||||
|
export const PopoverContent = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
hideCloseBtn,
|
||||||
|
...props
|
||||||
|
}: PopoverContentProps) => (
|
||||||
|
<PopoverPrimitive.Portal>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
className={twMerge(
|
||||||
|
[
|
||||||
|
'relative z-[100] w-64 rounded-md bg-mineshaft-600 fill-mineshaft-600 p-4 pt-6 font-inter text-gray-200 shadow-md',
|
||||||
|
// animation
|
||||||
|
'data-[state=open]:data-[side=bottom]:animate-slideUpAndFade',
|
||||||
|
'data-[state=open]:data-[side=top]:animate-slideDownAndFade',
|
||||||
|
'data-[state=open]:data-[side=left]:animate-slideRightAndFade',
|
||||||
|
'data-[state=open]:data-[side=right]:animate-slideLeftAndFade'
|
||||||
|
],
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{!hideCloseBtn && (
|
||||||
|
<PopoverPrimitive.Close aria-label="Close" asChild>
|
||||||
|
<IconButton
|
||||||
|
variant="plain"
|
||||||
|
ariaLabel="close"
|
||||||
|
className="absolute top-0 right-1 rounded text-bunker-400 hover:text-bunker-50"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTimes} size="lg" className="cursor-pointer" />
|
||||||
|
</IconButton>
|
||||||
|
</PopoverPrimitive.Close>
|
||||||
|
)}
|
||||||
|
<PopoverPrimitive.Arrow className="fill-inherit" />
|
||||||
|
</PopoverPrimitive.Content>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
|
);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { Popover,PopoverContent, PopoverTrigger } from './Popoverv2';
|
||||||
@@ -19,7 +19,7 @@ export const Switch = ({
|
|||||||
isRequired,
|
isRequired,
|
||||||
...props
|
...props
|
||||||
}: SwitchProps): JSX.Element => (
|
}: SwitchProps): JSX.Element => (
|
||||||
<div className="flex items-center text-bunker-300 font-inter">
|
<div className="flex items-center font-inter text-bunker-300">
|
||||||
<label className="text-sm" htmlFor={id}>
|
<label className="text-sm" htmlFor={id}>
|
||||||
{children}
|
{children}
|
||||||
{isRequired && <span className="pl-1 text-red">*</span>}
|
{isRequired && <span className="pl-1 text-red">*</span>}
|
||||||
@@ -30,13 +30,13 @@ export const Switch = ({
|
|||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'h-5 ml-3 transition-all rounded-full w-9 bg-bunker-300 data-[state=checked]:bg-bunker-200',
|
'ml-3 h-5 w-9 rounded-full bg-bunker-300 transition-all data-[state=checked]:bg-primary',
|
||||||
isDisabled && 'bg-bunker-400 hover:bg-bunker-400',
|
isDisabled && 'bg-bunker-400 hover:bg-bunker-400',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
id={id}
|
id={id}
|
||||||
>
|
>
|
||||||
<SwitchPrimitive.Thumb className="w-4 h-4 border-none will-change-transform rounded-full shadow bg-black block transition-all translate-x-0.5 data-[state=checked]:translate-x-[18px]" />
|
<SwitchPrimitive.Thumb className="block h-4 w-4 translate-x-0.5 rounded-full border-none bg-black shadow transition-all will-change-transform data-[state=checked]:translate-x-[18px]" />
|
||||||
</SwitchPrimitive.Root>
|
</SwitchPrimitive.Root>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,24 +1,56 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import { faClose } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { cva, VariantProps } from 'cva';
|
import { cva, VariantProps } from 'cva';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onClose?: () => void;
|
||||||
|
color?: string;
|
||||||
|
isDisabled?: boolean;
|
||||||
} & VariantProps<typeof tagVariants>;
|
} & VariantProps<typeof tagVariants>;
|
||||||
|
|
||||||
const tagVariants = cva('inline-flex whitespace-nowrap text-sm rounded-sm mr-1.5 text-bunker-200 ', {
|
const tagVariants = cva(
|
||||||
variants: {
|
'inline-flex items-center whitespace-nowrap text-sm rounded-sm mr-1.5 text-bunker-200',
|
||||||
colorSchema: {
|
{
|
||||||
gray: 'bg-mineshaft-500',
|
variants: {
|
||||||
red: 'bg-red/80 text-bunker-100'
|
colorSchema: {
|
||||||
},
|
gray: 'bg-mineshaft-500',
|
||||||
size: {
|
red: 'bg-red/80 text-bunker-100',
|
||||||
sm: 'px-1.5 py-0.5'
|
green: 'bg-primary-800 text-white'
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: 'px-2 py-0.5'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
export const Tag = ({ children, className, colorSchema = 'gray', size = 'sm' }: Props) => (
|
export const Tag = ({
|
||||||
<div className={twMerge(tagVariants({ colorSchema, className, size }))}>{children}</div>
|
children,
|
||||||
|
className,
|
||||||
|
colorSchema = 'gray',
|
||||||
|
color,
|
||||||
|
isDisabled,
|
||||||
|
size = 'sm',
|
||||||
|
onClose
|
||||||
|
}: Props) => (
|
||||||
|
<div
|
||||||
|
className={twMerge(tagVariants({ colorSchema, className, size }))}
|
||||||
|
style={{ backgroundColor: color }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{onClose && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onClose}
|
||||||
|
disabled={isDisabled}
|
||||||
|
className="ml-2 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faClose} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { cva, VariantProps } from 'cva';
|
|||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
isDisabled?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
isFullWidth?: boolean;
|
isFullWidth?: boolean;
|
||||||
isRequired?: boolean;
|
isRequired?: boolean;
|
||||||
@@ -10,7 +11,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const textAreaVariants = cva(
|
const textAreaVariants = cva(
|
||||||
'textarea w-full p-2 border border-solid text-gray-400 font-inter placeholder-gray-500 placeholder-opacity-50',
|
'textarea w-full p-2 focus:ring-2 ring-primary-800 outline-none border border-solid text-gray-400 font-inter placeholder-gray-500 placeholder-opacity-50',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
@@ -43,7 +44,7 @@ const textAreaVariants = cva(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TextAreaProps = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'> &
|
export type TextAreaProps = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'size' | 'disabled'> &
|
||||||
VariantProps<typeof textAreaVariants> &
|
VariantProps<typeof textAreaVariants> &
|
||||||
Props;
|
Props;
|
||||||
|
|
||||||
@@ -52,6 +53,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|||||||
{
|
{
|
||||||
className,
|
className,
|
||||||
isRounded = true,
|
isRounded = true,
|
||||||
|
isDisabled = false,
|
||||||
isError = false,
|
isError = false,
|
||||||
isRequired,
|
isRequired,
|
||||||
variant = 'filled',
|
variant = 'filled',
|
||||||
@@ -66,6 +68,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
|||||||
style={{ resize: reSize }}
|
style={{ resize: reSize }}
|
||||||
required={isRequired}
|
required={isRequired}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
disabled={isDisabled}
|
||||||
className={twMerge(textAreaVariants({ className, isError, size, isRounded, variant }))}
|
className={twMerge(textAreaVariants({ className, isError, size, isRounded, variant }))}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { Tooltip, TooltipProps, TooltipProvider } from './Tooltip';
|
||||||
|
|
||||||
|
const meta: Meta<typeof Tooltip> = {
|
||||||
|
title: 'Components/Tooltip',
|
||||||
|
component: Tooltip,
|
||||||
|
tags: ['v2'],
|
||||||
|
args: {
|
||||||
|
content: 'Hi'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof Tooltip>;
|
||||||
|
|
||||||
|
const Template = (args: TooltipProps) => (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip {...args}>
|
||||||
|
<div className="text-white">Hello infisical</div>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args
|
||||||
|
export const Primary: Story = {
|
||||||
|
render: (args) => <Template {...args} />
|
||||||
|
};
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
export type TooltipProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
content?: ReactNode;
|
||||||
|
isOpen?: boolean;
|
||||||
|
className?: string;
|
||||||
|
asChild?: boolean;
|
||||||
|
onOpenChange?: (isOpen: boolean) => void;
|
||||||
|
defaultOpen?: boolean;
|
||||||
|
} & Omit<TooltipPrimitive.TooltipContentProps, 'open'>;
|
||||||
|
|
||||||
|
export const Tooltip = ({
|
||||||
|
children,
|
||||||
|
content,
|
||||||
|
isOpen,
|
||||||
|
onOpenChange,
|
||||||
|
defaultOpen,
|
||||||
|
className,
|
||||||
|
asChild = true,
|
||||||
|
...props
|
||||||
|
}: TooltipProps) => (
|
||||||
|
<TooltipPrimitive.Root
|
||||||
|
delayDuration={150}
|
||||||
|
open={isOpen}
|
||||||
|
defaultOpen={defaultOpen}
|
||||||
|
onOpenChange={onOpenChange}
|
||||||
|
>
|
||||||
|
<TooltipPrimitive.Trigger asChild={asChild}>{children}</TooltipPrimitive.Trigger>
|
||||||
|
<TooltipPrimitive.Content
|
||||||
|
side="top"
|
||||||
|
align="center"
|
||||||
|
sideOffset={5}
|
||||||
|
{...props}
|
||||||
|
className={twMerge(
|
||||||
|
`z-20 select-none rounded-md bg-mineshaft-500 py-2 px-4 text-sm shadow-md
|
||||||
|
data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade
|
||||||
|
data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade
|
||||||
|
data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade
|
||||||
|
data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade
|
||||||
|
`,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
<TooltipPrimitive.Arrow width={11} height={5} className="fill-mineshaft-500" />
|
||||||
|
</TooltipPrimitive.Content>
|
||||||
|
</TooltipPrimitive.Root>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const TooltipProvider = TooltipPrimitive.Provider;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { Tooltip, TooltipProvider } from './Tooltip';
|
||||||
@@ -2,14 +2,17 @@ export * from './Button';
|
|||||||
export * from './Card';
|
export * from './Card';
|
||||||
export * from './Checkbox';
|
export * from './Checkbox';
|
||||||
export * from './DeleteActionModal';
|
export * from './DeleteActionModal';
|
||||||
|
export * from './Drawer';
|
||||||
export * from './Dropdown';
|
export * from './Dropdown';
|
||||||
export * from './EmailServiceSetupModal'
|
export * from './EmailServiceSetupModal'
|
||||||
export * from './EmptyState';
|
export * from './EmptyState';
|
||||||
export * from './FormControl';
|
export * from './FormControl';
|
||||||
|
export * from './HoverCardv2';
|
||||||
export * from './IconButton';
|
export * from './IconButton';
|
||||||
export * from './Input';
|
export * from './Input';
|
||||||
export * from './Menu';
|
export * from './Menu';
|
||||||
export * from './Modal';
|
export * from './Modal';
|
||||||
|
export * from './Popoverv2';
|
||||||
export * from './Select';
|
export * from './Select';
|
||||||
export * from './Skeleton';
|
export * from './Skeleton';
|
||||||
export * from './Spinner';
|
export * from './Spinner';
|
||||||
@@ -17,4 +20,5 @@ export * from './Switch';
|
|||||||
export * from './Table';
|
export * from './Table';
|
||||||
export * from './Tag';
|
export * from './Tag';
|
||||||
export * from './TextArea';
|
export * from './TextArea';
|
||||||
|
export * from './Tooltip';
|
||||||
export * from './UpgradePlanModal';
|
export * from './UpgradePlanModal';
|
||||||
|
|||||||
Reference in New Issue
Block a user