Remove redundant files and update pnpm lockfile
This commit is contained in:
@@ -144,7 +144,7 @@ export function AccountSelector({
|
||||
)}
|
||||
</If>
|
||||
|
||||
<CaretSortIcon className="h-4 w-4 shrink-0 opacity-50" />
|
||||
<CaretSortIcon className="ml-1 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
|
||||
|
||||
@@ -115,15 +115,15 @@ export function PersonalAccountDropdown({
|
||||
</div>
|
||||
|
||||
<EllipsisVertical
|
||||
className={'text-muted-foreground hidden h-8 group-hover:flex'}
|
||||
className={'text-muted-foreground mr-1 hidden h-8 group-hover:flex'}
|
||||
/>
|
||||
</If>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent
|
||||
className={'!min-w-[15rem]'}
|
||||
className={'xl:!min-w-[15rem]'}
|
||||
collisionPadding={{ right: 20, left: 20 }}
|
||||
sideOffset={20}
|
||||
sideOffset={10}
|
||||
>
|
||||
<DropdownMenuItem className={'!h-10 rounded-none'}>
|
||||
<div
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import type { Factor } from '@supabase/supabase-js';
|
||||
@@ -25,7 +27,7 @@ import {
|
||||
import { Badge } from '@kit/ui/badge';
|
||||
import { Button } from '@kit/ui/button';
|
||||
import { If } from '@kit/ui/if';
|
||||
import Spinner from '@kit/ui/spinner';
|
||||
import { Spinner } from '@kit/ui/spinner';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
InputOTPSeparator,
|
||||
InputOTPSlot,
|
||||
} from '@kit/ui/input-otp';
|
||||
import Spinner from '@kit/ui/spinner';
|
||||
import { Spinner } from '@kit/ui/spinner';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
export function MultiFactorChallengeContainer({
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "^2.42.7",
|
||||
"@tanstack/react-query": "5.32.0",
|
||||
"@types/react": "^18.3.1",
|
||||
"lucide-react": "^0.376.0",
|
||||
"react": "18.3.1",
|
||||
|
||||
@@ -128,8 +128,9 @@ export function NotificationsPopover(params: {
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent
|
||||
className={'flex flex-col p-0'}
|
||||
className={'flex w-full flex-col p-0 lg:min-w-64'}
|
||||
collisionPadding={{ right: 20 }}
|
||||
sideOffset={10}
|
||||
>
|
||||
<div className={'flex items-center px-3 py-2 text-sm font-semibold'}>
|
||||
{t('common:notifications')}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
|
||||
|
||||
@@ -20,8 +22,8 @@ export function useFetchNotifications({
|
||||
accountIds: string[];
|
||||
realtime: boolean;
|
||||
}) {
|
||||
const { data: notifications } = useFetchInitialNotifications({ accountIds });
|
||||
const client = useSupabase();
|
||||
const didFetchInitialData = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
let realtimeSubscription: { unsubscribe: () => void } | null = null;
|
||||
@@ -45,10 +47,26 @@ export function useFetchNotifications({
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
if (!didFetchInitialData.current) {
|
||||
const now = new Date().toISOString();
|
||||
if (notifications) {
|
||||
onNotifications(notifications);
|
||||
}
|
||||
|
||||
const initialFetch = client
|
||||
return () => {
|
||||
if (realtimeSubscription) {
|
||||
realtimeSubscription.unsubscribe();
|
||||
}
|
||||
};
|
||||
}, [client, onNotifications, accountIds, realtime, notifications]);
|
||||
}
|
||||
|
||||
function useFetchInitialNotifications(props: { accountIds: string[] }) {
|
||||
const client = useSupabase();
|
||||
const now = new Date().toISOString();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['notifications', ...props.accountIds],
|
||||
queryFn: async () => {
|
||||
const { data } = await client
|
||||
.from('notifications')
|
||||
.select(
|
||||
`id,
|
||||
@@ -59,29 +77,14 @@ export function useFetchNotifications({
|
||||
link
|
||||
`,
|
||||
)
|
||||
.in('account_id', accountIds)
|
||||
.in('account_id', props.accountIds)
|
||||
.eq('dismissed', false)
|
||||
.gt('expires_at', now)
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(10);
|
||||
|
||||
didFetchInitialData.current = true;
|
||||
|
||||
void initialFetch.then(({ data, error }) => {
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
onNotifications(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (realtimeSubscription) {
|
||||
realtimeSubscription.unsubscribe();
|
||||
}
|
||||
};
|
||||
}, [client, onNotifications, accountIds, realtime]);
|
||||
return data;
|
||||
},
|
||||
refetchOnMount: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -217,7 +217,6 @@ function ActionsDropdown({
|
||||
<UpdateInvitationDialog
|
||||
isOpen
|
||||
setIsOpen={setIsUpdatingRole}
|
||||
account={invitation.account_id}
|
||||
invitationId={invitation.id}
|
||||
userRole={invitation.role}
|
||||
userRoleHierarchy={permissions.currentUserRoleHierarchy}
|
||||
|
||||
@@ -36,17 +36,9 @@ export const UpdateInvitationDialog: React.FC<{
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
invitationId: number;
|
||||
account: string;
|
||||
userRole: Role;
|
||||
userRoleHierarchy: number;
|
||||
}> = ({
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
invitationId,
|
||||
userRole,
|
||||
userRoleHierarchy,
|
||||
account,
|
||||
}) => {
|
||||
}> = ({ isOpen, setIsOpen, invitationId, userRole, userRoleHierarchy }) => {
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogContent>
|
||||
@@ -61,7 +53,6 @@ export const UpdateInvitationDialog: React.FC<{
|
||||
</DialogHeader>
|
||||
|
||||
<UpdateInvitationForm
|
||||
account={account}
|
||||
invitationId={invitationId}
|
||||
userRole={userRole}
|
||||
userRoleHierarchy={userRoleHierarchy}
|
||||
@@ -73,13 +64,11 @@ export const UpdateInvitationDialog: React.FC<{
|
||||
};
|
||||
|
||||
function UpdateInvitationForm({
|
||||
account,
|
||||
invitationId,
|
||||
userRole,
|
||||
userRoleHierarchy,
|
||||
setIsOpen,
|
||||
}: React.PropsWithChildren<{
|
||||
account: string;
|
||||
invitationId: number;
|
||||
userRole: Role;
|
||||
userRoleHierarchy: number;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,7 +104,8 @@
|
||||
"./trans": "./src/makerkit/trans.tsx",
|
||||
"./divider": "./src/makerkit/divider.tsx",
|
||||
"./sidebar": "./src/makerkit/sidebar.tsx",
|
||||
"./sidebar-schema": "./src/makerkit/sidebar-schema.ts",
|
||||
"./navigation-schema": "./src/makerkit/navigation-config.schema.ts",
|
||||
"./bordered-navigation-menu": "./src/makerkit/bordered-navigation-menu.tsx",
|
||||
"./spinner": "./src/makerkit/spinner.tsx",
|
||||
"./page": "./src/makerkit/page.tsx",
|
||||
"./image-uploader": "./src/makerkit/image-uploader.tsx",
|
||||
|
||||
50
packages/ui/src/makerkit/bordered-navigation-menu.tsx
Normal file
50
packages/ui/src/makerkit/bordered-navigation-menu.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
import { Button } from '../shadcn/button';
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuList,
|
||||
} from '../shadcn/navigation-menu';
|
||||
import { cn, isRouteActive } from '../utils';
|
||||
import { Trans } from './trans';
|
||||
|
||||
export function BorderedNavigationMenu(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<NavigationMenu className={'h-full'}>
|
||||
<NavigationMenuList className={'relative h-full space-x-2'}>
|
||||
{props.children}
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
);
|
||||
}
|
||||
|
||||
export function BorderedNavigationMenuItem(props: {
|
||||
path: string;
|
||||
label: string;
|
||||
active?: boolean;
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
const active = props.active ?? isRouteActive(pathname, props.path);
|
||||
|
||||
return (
|
||||
<NavigationMenuItem>
|
||||
<Button asChild variant={'ghost'} className={'relative'}>
|
||||
<Link href={props.path} className={'text-sm'}>
|
||||
<Trans i18nKey={props.label} defaults={props.label} />
|
||||
|
||||
{active ? (
|
||||
<span
|
||||
className={cn(
|
||||
'absolute -bottom-2.5 left-0 h-1 w-full bg-primary animate-in fade-in zoom-in-90',
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
</Link>
|
||||
</Button>
|
||||
</NavigationMenuItem>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PropsWithChildren } from 'react';
|
||||
|
||||
import { cn } from '../utils';
|
||||
import Spinner from './spinner';
|
||||
import { Spinner } from './spinner';
|
||||
|
||||
export function LoadingOverlay({
|
||||
children,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const SidebarConfigSchema = z.object({
|
||||
export const NavigationConfigSchema = z.object({
|
||||
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
|
||||
routes: z.array(
|
||||
z.union([
|
||||
z.object({
|
||||
@@ -1,23 +1,98 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from '../utils';
|
||||
|
||||
export function Page(
|
||||
props: React.PropsWithChildren<{
|
||||
sidebar?: React.ReactNode;
|
||||
contentContainerClassName?: string;
|
||||
className?: string;
|
||||
}>,
|
||||
) {
|
||||
type PageStyle = 'sidebar' | 'header' | 'custom';
|
||||
|
||||
type PageProps = React.PropsWithChildren<{
|
||||
style?: PageStyle;
|
||||
contentContainerClassName?: string;
|
||||
className?: string;
|
||||
sticky?: boolean;
|
||||
}>;
|
||||
|
||||
export function Page(props: PageProps) {
|
||||
switch (props.style) {
|
||||
case 'sidebar':
|
||||
return <PageWithSidebar {...props} />;
|
||||
|
||||
case 'header':
|
||||
return <PageWithHeader {...props} />;
|
||||
|
||||
case 'custom':
|
||||
return props.children;
|
||||
|
||||
default:
|
||||
return <PageWithSidebar {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
function PageWithSidebar(props: PageProps) {
|
||||
const { Navigation, Children, MobileNavigation } = getSlotsFromPage(props);
|
||||
|
||||
return (
|
||||
<div className={cn('flex', props.className)}>
|
||||
<div className={'hidden lg:block'}>{props.sidebar}</div>
|
||||
{Navigation}
|
||||
|
||||
<div
|
||||
className={
|
||||
props.contentContainerClassName ??
|
||||
'mx-auto flex h-screen w-full flex-col space-y-4 overflow-y-auto'
|
||||
'mx-auto flex h-screen w-full flex-col overflow-y-auto px-4 lg:px-0'
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
{MobileNavigation}
|
||||
|
||||
<div className={'flex flex-col space-y-4 lg:mt-4 lg:px-4'}>
|
||||
{Children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function PageMobileNavigation(
|
||||
props: React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>,
|
||||
) {
|
||||
return (
|
||||
<div className={cn('w-full py-4 lg:hidden', props.className)}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PageWithHeader(props: PageProps) {
|
||||
const { Navigation, Children, MobileNavigation } = getSlotsFromPage(props);
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-1 flex-col', props.className)}>
|
||||
<div
|
||||
className={
|
||||
props.contentContainerClassName ?? 'flex flex-1 flex-col space-y-4'
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'dark:border-primary-900 flex h-14 items-center justify-between px-4 shadow-sm dark:shadow-primary/10 lg:justify-start',
|
||||
{
|
||||
'sticky top-0 z-10 bg-background/80 backdrop-blur-md':
|
||||
props.sticky ?? true,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={'hidden w-full flex-1 items-center space-x-8 lg:flex'}
|
||||
>
|
||||
{Navigation}
|
||||
</div>
|
||||
|
||||
{MobileNavigation}
|
||||
</div>
|
||||
|
||||
<div className={'flex flex-col space-y-8 px-4 py-4 lg:container'}>
|
||||
{Children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -28,50 +103,54 @@ export function PageBody(
|
||||
className?: string;
|
||||
}>,
|
||||
) {
|
||||
const className = cn('w-full px-4 flex flex-col flex-1', props.className);
|
||||
const className = cn('w-full flex flex-col flex-1', props.className);
|
||||
|
||||
return <div className={className}>{props.children}</div>;
|
||||
}
|
||||
|
||||
export function PageNavigation(props: React.PropsWithChildren) {
|
||||
return <div className={'hidden flex-1 lg:flex'}>{props.children}</div>;
|
||||
}
|
||||
|
||||
export function PageDescription(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<h2 className={'hidden lg:block'}>
|
||||
<span
|
||||
className={'text-base font-medium leading-none text-muted-foreground'}
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
export function PageTitle(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<h1
|
||||
className={
|
||||
'font-heading text-2xl font-semibold leading-none dark:text-white'
|
||||
}
|
||||
>
|
||||
{props.children}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
export function PageHeader({
|
||||
children,
|
||||
title,
|
||||
description,
|
||||
mobileNavigation,
|
||||
}: React.PropsWithChildren<{
|
||||
title?: string | React.ReactNode;
|
||||
description?: string | React.ReactNode;
|
||||
mobileNavigation?: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<div className={'flex min-h-[4.5rem] items-center justify-between px-4'}>
|
||||
<div className={'flex items-center justify-between'}>
|
||||
{title ? (
|
||||
<div
|
||||
className={
|
||||
'flex items-center space-x-4 lg:flex-col lg:items-start lg:space-x-0 lg:space-y-0.5'
|
||||
}
|
||||
>
|
||||
<div className={'flex items-center lg:hidden'}>
|
||||
{mobileNavigation}
|
||||
</div>
|
||||
<div className={'flex flex-col space-y-1.5'}>
|
||||
<PageTitle>{title}</PageTitle>
|
||||
|
||||
<h1
|
||||
className={
|
||||
'font-heading text-xl font-semibold leading-none dark:text-white'
|
||||
}
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
|
||||
<h2 className={'hidden lg:block'}>
|
||||
<span
|
||||
className={
|
||||
'text-base font-medium leading-none text-muted-foreground'
|
||||
}
|
||||
>
|
||||
{description}
|
||||
</span>
|
||||
</h2>
|
||||
<PageDescription>{description}</PageDescription>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -79,3 +158,41 @@ export function PageHeader({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function getSlotsFromPage(props: React.PropsWithChildren) {
|
||||
return React.Children.toArray(props.children).reduce<{
|
||||
Children: React.ReactElement | null;
|
||||
Navigation: React.ReactElement | null;
|
||||
MobileNavigation: React.ReactElement | null;
|
||||
}>(
|
||||
(acc, child) => {
|
||||
if (!React.isValidElement(child)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (child.type === PageNavigation) {
|
||||
return {
|
||||
...acc,
|
||||
Navigation: child,
|
||||
};
|
||||
}
|
||||
|
||||
if (child.type === PageMobileNavigation) {
|
||||
return {
|
||||
...acc,
|
||||
MobileNavigation: child,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
Children: child,
|
||||
};
|
||||
},
|
||||
{
|
||||
Children: null,
|
||||
Navigation: null,
|
||||
MobileNavigation: null,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import {
|
||||
import { cn, isRouteActive } from '../utils';
|
||||
import { SidebarContext } from './context/sidebar.context';
|
||||
import { If } from './if';
|
||||
import { SidebarConfigSchema } from './sidebar-schema';
|
||||
import { NavigationConfigSchema } from './navigation-config.schema';
|
||||
import { Trans } from './trans';
|
||||
|
||||
export type SidebarConfig = z.infer<typeof SidebarConfigSchema>;
|
||||
export type SidebarConfig = z.infer<typeof NavigationConfigSchema>;
|
||||
|
||||
export function Sidebar(props: {
|
||||
collapsed?: boolean;
|
||||
@@ -167,7 +167,7 @@ export function SidebarItem({
|
||||
<Button
|
||||
asChild
|
||||
className={cn('flex w-full text-sm shadow-none', {
|
||||
'justify-start space-x-2': !collapsed,
|
||||
'justify-start space-x-2.5': !collapsed,
|
||||
})}
|
||||
size={size}
|
||||
variant={variant}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { cn } from '../utils/cn';
|
||||
import { cn } from '../utils';
|
||||
|
||||
function Spinner(
|
||||
export function Spinner(
|
||||
props: React.PropsWithChildren<{
|
||||
className?: string;
|
||||
}>,
|
||||
@@ -29,5 +29,3 @@ function Spinner(
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Spinner;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"use client"
|
||||
'use client';
|
||||
|
||||
import * as React from "react"
|
||||
import * as SwitchPrimitives from "@radix-ui/react-switch"
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from "@kit/ui/utils"
|
||||
import * as SwitchPrimitives from '@radix-ui/react-switch';
|
||||
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
const Switch = React.forwardRef<
|
||||
React.ElementRef<typeof SwitchPrimitives.Root>,
|
||||
@@ -11,19 +12,19 @@ const Switch = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
||||
className
|
||||
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb
|
||||
className={cn(
|
||||
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
||||
'pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0',
|
||||
)}
|
||||
/>
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
));
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName;
|
||||
|
||||
export { Switch }
|
||||
export { Switch };
|
||||
|
||||
Reference in New Issue
Block a user