2.18.0: New Invitation flow, refactored Database Webhooks, new ShadCN UI Components (#384)
* Streamlined invitations flow * Removed web hooks in favor of handling logic directly in server actions * Added new Shadcn UI Components
This commit is contained in:
committed by
GitHub
parent
195cf41680
commit
2e20d3e76f
@@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
|
||||
import { cn } from '../lib/utils';
|
||||
import { Button } from '../shadcn/button';
|
||||
|
||||
@@ -8,7 +10,7 @@ const EmptyStateHeading: React.FC<React.HTMLAttributes<HTMLHeadingElement>> = ({
|
||||
...props
|
||||
}) => (
|
||||
<h3
|
||||
className={cn('text-2xl font-bold tracking-tight', className)}
|
||||
className={cn('text-lg font-medium tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -49,7 +51,16 @@ const EmptyState: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
||||
(child) => React.isValidElement(child) && child.type === EmptyStateButton,
|
||||
);
|
||||
|
||||
const cmps = [EmptyStateHeading, EmptyStateText, EmptyStateButton];
|
||||
const media = childrenArray.find(
|
||||
(child) => React.isValidElement(child) && child.type === EmptyMedia,
|
||||
);
|
||||
|
||||
const cmps = [
|
||||
EmptyStateHeading,
|
||||
EmptyStateText,
|
||||
EmptyStateButton,
|
||||
EmptyMedia,
|
||||
];
|
||||
|
||||
const otherChildren = childrenArray.filter(
|
||||
(child) =>
|
||||
@@ -66,6 +77,7 @@ const EmptyState: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
||||
{...props}
|
||||
>
|
||||
<div className="flex flex-col items-center gap-1 text-center">
|
||||
{media}
|
||||
{heading}
|
||||
{text}
|
||||
{button}
|
||||
@@ -76,4 +88,40 @@ const EmptyState: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
||||
};
|
||||
EmptyState.displayName = 'EmptyState';
|
||||
|
||||
export { EmptyState, EmptyStateHeading, EmptyStateText, EmptyStateButton };
|
||||
const emptyMediaVariants = cva(
|
||||
'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-transparent',
|
||||
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
function EmptyMedia({
|
||||
className,
|
||||
variant = 'default',
|
||||
...props
|
||||
}: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
|
||||
return (
|
||||
<div
|
||||
data-slot="empty-icon"
|
||||
data-variant={variant}
|
||||
className={cn(emptyMediaVariants({ variant, className }))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
EmptyState,
|
||||
EmptyStateHeading,
|
||||
EmptyStateText,
|
||||
EmptyStateButton,
|
||||
EmptyMedia,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ export function GlobalLoader({
|
||||
<If condition={displaySpinner}>
|
||||
<div
|
||||
className={
|
||||
'zoom-in-80 animate-in fade-in slide-in-from-bottom-12 flex flex-1 flex-col items-center justify-center duration-500'
|
||||
'zoom-in-80 animate-in fade-in slide-in-from-bottom-12 flex flex-1 flex-col items-center justify-center duration-500 ease-out'
|
||||
}
|
||||
>
|
||||
<LoadingOverlay displayLogo={displayLogo} fullPage={fullPage} />
|
||||
|
||||
@@ -33,8 +33,8 @@ export function OauthProviderLogoImage({
|
||||
|
||||
function getOAuthProviderLogos(): Record<string, string | React.ReactNode> {
|
||||
return {
|
||||
email: <AtSign className={'size-[18px]'} />,
|
||||
phone: <Phone className={'size-[18x]'} />,
|
||||
email: <AtSign className={'size-[16px]'} />,
|
||||
phone: <Phone className={'size-[16px]'} />,
|
||||
google: '/images/oauth/google.webp',
|
||||
facebook: '/images/oauth/facebook.webp',
|
||||
github: '/images/oauth/github.webp',
|
||||
|
||||
@@ -1,36 +1,16 @@
|
||||
import { cn } from '../lib/utils';
|
||||
import { Loader2Icon } from 'lucide-react';
|
||||
|
||||
export function Spinner(
|
||||
props: React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>,
|
||||
) {
|
||||
import { cn } from '../lib/utils/cn';
|
||||
|
||||
function Spinner({ className, ...props }: React.ComponentProps<'svg'>) {
|
||||
return (
|
||||
<div role="status" aria-label="loading">
|
||||
<svg
|
||||
className={cn(
|
||||
props.className,
|
||||
'stroke-muted-foreground h-6 w-6 animate-spin',
|
||||
)}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_9023_61563)">
|
||||
<path
|
||||
d="M14.6437 2.05426C11.9803 1.2966 9.01686 1.64245 6.50315 3.25548C1.85499 6.23817 0.504864 12.4242 3.48756 17.0724C6.47025 21.7205 12.6563 23.0706 17.3044 20.088C20.4971 18.0393 22.1338 14.4793 21.8792 10.9444"
|
||||
stroke="stroke-current"
|
||||
strokeWidth="1.4"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<defs>
|
||||
<clipPath id="clip0_9023_61563">
|
||||
<rect width="24" height="24" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<Loader2Icon
|
||||
role="status"
|
||||
aria-label="Loading"
|
||||
className={cn('text-muted-foreground size-6 animate-spin', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { Spinner };
|
||||
|
||||
Reference in New Issue
Block a user