mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(ui): added ui components for new dashboard
This commit is contained in:
@@ -20,7 +20,7 @@ type EncryptAsymmetricProps = {
|
||||
* @param {Number} obj.time - number of iterations
|
||||
* @param {Number} obj.parallelism - desired parallelism
|
||||
* @param {Number} obj.hashLen - desired hash length (i.e. byte-length of derived key)
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
const deriveArgonKey = async ({
|
||||
password,
|
||||
@@ -39,8 +39,8 @@ const deriveArgonKey = async ({
|
||||
}) => {
|
||||
let derivedKey;
|
||||
try {
|
||||
derivedKey = await argon2.hash({
|
||||
pass: password,
|
||||
derivedKey = await argon2.hash({
|
||||
pass: password,
|
||||
salt,
|
||||
type: argon2.ArgonType.Argon2id,
|
||||
mem,
|
||||
@@ -53,7 +53,7 @@ const deriveArgonKey = async ({
|
||||
}
|
||||
|
||||
return derivedKey;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return assymmetrically encrypted [plaintext] using [publicKey] where
|
||||
@@ -173,6 +173,7 @@ type DecryptSymmetricProps = {
|
||||
*
|
||||
*/
|
||||
const decryptSymmetric = ({ ciphertext, iv, tag, key }: DecryptSymmetricProps): string => {
|
||||
if (!ciphertext) return '';
|
||||
let plaintext;
|
||||
try {
|
||||
plaintext = aes.decrypt({ ciphertext, iv, tag, secret: key });
|
||||
@@ -184,10 +185,10 @@ const decryptSymmetric = ({ ciphertext, iv, tag, key }: DecryptSymmetricProps):
|
||||
return plaintext;
|
||||
};
|
||||
|
||||
export {
|
||||
decryptAssymmetric,
|
||||
decryptSymmetric,
|
||||
export {
|
||||
decryptAssymmetric,
|
||||
decryptSymmetric,
|
||||
deriveArgonKey,
|
||||
encryptAssymmetric,
|
||||
encryptSymmetric
|
||||
encryptAssymmetric,
|
||||
encryptSymmetric
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ const buttonVariants = cva(
|
||||
star: 'text-bunker-200 bg-mineshaft-500'
|
||||
},
|
||||
isDisabled: {
|
||||
true: 'bg-mineshaft opacity-40 cursor-not-allowed',
|
||||
true: 'bg-mineshaft text-white opacity-50 cursor-not-allowed',
|
||||
false: ''
|
||||
},
|
||||
isFullWidth: {
|
||||
@@ -155,26 +155,26 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
className="absolute rounded-xl"
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
<div
|
||||
className={twMerge(
|
||||
'shrink-0 cursor-pointer transition-all',
|
||||
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
|
||||
loadingToggleClass,
|
||||
leftIcon && 'ml-2',
|
||||
size === 'xs' ? 'mr-1' : 'mr-3'
|
||||
size === 'xs' ? 'mr-1' : 'mr-2'
|
||||
)}
|
||||
>
|
||||
{leftIcon}
|
||||
</span>
|
||||
<span className={twMerge('transition-all', loadingToggleClass)}>{children}</span>
|
||||
<span
|
||||
</div>
|
||||
<span className={twMerge('w-full transition-all', loadingToggleClass)}>{children}</span>
|
||||
<div
|
||||
className={twMerge(
|
||||
'shrink-0 cursor-pointer transition-all',
|
||||
'inline-flex shrink-0 cursor-pointer items-center justify-center transition-all',
|
||||
loadingToggleClass,
|
||||
size === 'xs' ? 'ml-1' : 'ml-3'
|
||||
size === 'xs' ? 'ml-1' : 'ml-2'
|
||||
)}
|
||||
>
|
||||
{rightIcon}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
32
frontend/src/components/v2/Drawer/Drawer.stories.tsx
Normal file
32
frontend/src/components/v2/Drawer/Drawer.stories.tsx
Normal file
@@ -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'
|
||||
}
|
||||
};
|
||||
84
frontend/src/components/v2/Drawer/Drawer.tsx
Normal file
84
frontend/src/components/v2/Drawer/Drawer.tsx
Normal file
@@ -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;
|
||||
1
frontend/src/components/v2/Drawer/index.tsx
Normal file
1
frontend/src/components/v2/Drawer/index.tsx
Normal file
@@ -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} />
|
||||
};
|
||||
26
frontend/src/components/v2/HoverCardv2/HoverCardv2.tsx
Normal file
26
frontend/src/components/v2/HoverCardv2/HoverCardv2.tsx
Normal file
@@ -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>
|
||||
);
|
||||
1
frontend/src/components/v2/HoverCardv2/index.tsx
Normal file
1
frontend/src/components/v2/HoverCardv2/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { HoverCard,HoverCardContent, HoverCardTrigger } from './HoverCardv2';
|
||||
@@ -29,7 +29,8 @@ const iconButtonVariants = cva(
|
||||
variant: {
|
||||
solid: '',
|
||||
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
||||
plain: ''
|
||||
plain: '',
|
||||
star: 'text-bunker-200 bg-mineshaft-500'
|
||||
},
|
||||
isDisabled: {
|
||||
true: 'bg-opacity-70 cursor-not-allowed',
|
||||
@@ -40,13 +41,23 @@ const iconButtonVariants = cva(
|
||||
false: ''
|
||||
},
|
||||
size: {
|
||||
xs: ['text-xs', 'py-2', 'px-2'],
|
||||
xs: ['text-xs', 'py-1.5', 'px-2'],
|
||||
sm: ['text-sm', 'py-3', 'px-3'],
|
||||
md: ['text-md', 'py-4', 'px-4'],
|
||||
lg: ['text-lg', 'py-6', 'px-6']
|
||||
}
|
||||
},
|
||||
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',
|
||||
variant: 'outline',
|
||||
|
||||
@@ -9,6 +9,7 @@ type Props = {
|
||||
leftIcon?: ReactNode;
|
||||
rightIcon?: ReactNode;
|
||||
isDisabled?: boolean;
|
||||
isReadOnly?: boolean;
|
||||
};
|
||||
|
||||
const inputVariants = cva(
|
||||
@@ -78,6 +79,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
rightIcon,
|
||||
variant = 'filled',
|
||||
size = 'md',
|
||||
isReadOnly,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
@@ -89,6 +91,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
{...props}
|
||||
required={isRequired}
|
||||
ref={ref}
|
||||
readOnly={isReadOnly}
|
||||
disabled={isDisabled}
|
||||
className={twMerge(
|
||||
leftIcon ? 'pl-10' : 'pl-2.5',
|
||||
|
||||
@@ -12,20 +12,24 @@ export type ModalContentProps = DialogPrimitive.DialogContentProps & {
|
||||
subTitle?: ReactNode;
|
||||
footerContent?: ReactNode;
|
||||
onClose?: () => void;
|
||||
overlayClassName?: string;
|
||||
};
|
||||
|
||||
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.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)' }}
|
||||
/>
|
||||
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
||||
<Card
|
||||
isRounded
|
||||
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
|
||||
)}
|
||||
>
|
||||
|
||||
29
frontend/src/components/v2/Popoverv2/Popoverv2.stories.tsx
Normal file
29
frontend/src/components/v2/Popoverv2/Popoverv2.stories.tsx
Normal file
@@ -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} />
|
||||
};
|
||||
54
frontend/src/components/v2/Popoverv2/Popoverv2.tsx
Normal file
54
frontend/src/components/v2/Popoverv2/Popoverv2.tsx
Normal file
@@ -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>
|
||||
);
|
||||
1
frontend/src/components/v2/Popoverv2/index.tsx
Normal file
1
frontend/src/components/v2/Popoverv2/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { Popover,PopoverContent, PopoverTrigger } from './Popoverv2';
|
||||
@@ -19,7 +19,7 @@ export const Switch = ({
|
||||
isRequired,
|
||||
...props
|
||||
}: 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}>
|
||||
{children}
|
||||
{isRequired && <span className="pl-1 text-red">*</span>}
|
||||
@@ -30,13 +30,13 @@ export const Switch = ({
|
||||
checked={isChecked}
|
||||
disabled={isDisabled}
|
||||
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',
|
||||
className
|
||||
)}
|
||||
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>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,24 +1,56 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { faClose } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { cva, VariantProps } from 'cva';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
onClose?: () => void;
|
||||
color?: string;
|
||||
isDisabled?: boolean;
|
||||
} & VariantProps<typeof tagVariants>;
|
||||
|
||||
const tagVariants = cva('inline-flex whitespace-nowrap text-sm rounded-sm mr-1.5 text-bunker-200 ', {
|
||||
variants: {
|
||||
colorSchema: {
|
||||
gray: 'bg-mineshaft-500',
|
||||
red: 'bg-red/80 text-bunker-100'
|
||||
},
|
||||
size: {
|
||||
sm: 'px-1.5 py-0.5'
|
||||
const tagVariants = cva(
|
||||
'inline-flex items-center whitespace-nowrap text-sm rounded-sm mr-1.5 text-bunker-200',
|
||||
{
|
||||
variants: {
|
||||
colorSchema: {
|
||||
gray: 'bg-mineshaft-500',
|
||||
red: 'bg-red/80 text-bunker-100',
|
||||
green: 'bg-primary-800 text-white'
|
||||
},
|
||||
size: {
|
||||
sm: 'px-2 py-0.5'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const Tag = ({ children, className, colorSchema = 'gray', size = 'sm' }: Props) => (
|
||||
<div className={twMerge(tagVariants({ colorSchema, className, size }))}>{children}</div>
|
||||
);
|
||||
|
||||
export const Tag = ({
|
||||
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';
|
||||
|
||||
type Props = {
|
||||
isDisabled?: boolean;
|
||||
placeholder?: string;
|
||||
isFullWidth?: boolean;
|
||||
isRequired?: boolean;
|
||||
@@ -10,7 +11,7 @@ type Props = {
|
||||
};
|
||||
|
||||
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: {
|
||||
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> &
|
||||
Props;
|
||||
|
||||
@@ -52,6 +53,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
{
|
||||
className,
|
||||
isRounded = true,
|
||||
isDisabled = false,
|
||||
isError = false,
|
||||
isRequired,
|
||||
variant = 'filled',
|
||||
@@ -66,6 +68,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
style={{ resize: reSize }}
|
||||
required={isRequired}
|
||||
ref={ref}
|
||||
disabled={isDisabled}
|
||||
className={twMerge(textAreaVariants({ className, isError, size, isRounded, variant }))}
|
||||
/>
|
||||
)
|
||||
|
||||
28
frontend/src/components/v2/Tooltip/Tooltip.stories.tsx
Normal file
28
frontend/src/components/v2/Tooltip/Tooltip.stories.tsx
Normal file
@@ -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} />
|
||||
};
|
||||
53
frontend/src/components/v2/Tooltip/Tooltip.tsx
Normal file
53
frontend/src/components/v2/Tooltip/Tooltip.tsx
Normal file
@@ -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;
|
||||
1
frontend/src/components/v2/Tooltip/index.tsx
Normal file
1
frontend/src/components/v2/Tooltip/index.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export { Tooltip, TooltipProvider } from './Tooltip';
|
||||
@@ -2,14 +2,17 @@ export * from './Button';
|
||||
export * from './Card';
|
||||
export * from './Checkbox';
|
||||
export * from './DeleteActionModal';
|
||||
export * from './Drawer';
|
||||
export * from './Dropdown';
|
||||
export * from './EmailServiceSetupModal'
|
||||
export * from './EmptyState';
|
||||
export * from './FormControl';
|
||||
export * from './HoverCardv2';
|
||||
export * from './IconButton';
|
||||
export * from './Input';
|
||||
export * from './Menu';
|
||||
export * from './Modal';
|
||||
export * from './Popoverv2';
|
||||
export * from './Select';
|
||||
export * from './Skeleton';
|
||||
export * from './Spinner';
|
||||
@@ -17,4 +20,5 @@ export * from './Switch';
|
||||
export * from './Table';
|
||||
export * from './Tag';
|
||||
export * from './TextArea';
|
||||
export * from './Tooltip';
|
||||
export * from './UpgradePlanModal';
|
||||
|
||||
Reference in New Issue
Block a user