Enhanced Sidebar to support sub collapsible sections (#80)

* Enhanced Sidebar to support sub collapsible sections
* Data-Table: support getSortedRowModel
* Add missing renderAction; 
* Fix Sidebar on mobile
* Do not initialize Analytics Provider server side
* Do not bind i18Next until it's initialized
* Avoid infinite redirects in the auth path when Supabase emits a SIGNED_OUT event
* Force admin layout to be dynamic
This commit is contained in:
Giancarlo Buomprisco
2024-11-06 16:01:45 +01:00
committed by GitHub
parent 27ef8f7510
commit 465655fdd4
18 changed files with 322 additions and 160 deletions

View File

@@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation';
import {
flexRender,
getCoreRowModel,
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table';
import type {
@@ -45,6 +46,8 @@ interface ReactTableProps<T extends object> {
pageSize?: number;
pageCount?: number;
onPaginationChange?: (pagination: PaginationState) => void;
manualPagination?: boolean;
manualSorting?: boolean;
tableProps?: React.ComponentProps<typeof Table> &
Record<`data-${string}`, string>;
}
@@ -57,6 +60,8 @@ export function DataTable<T extends object>({
pageCount,
onPaginationChange,
tableProps,
manualPagination = true,
manualSorting = false,
}: ReactTableProps<T>) {
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: pageIndex ?? 0,
@@ -74,7 +79,9 @@ export function DataTable<T extends object>({
data,
columns,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
getSortedRowModel: getSortedRowModel(),
manualPagination,
manualSorting,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility,

View File

@@ -9,25 +9,32 @@ const Divider = z.object({
divider: z.literal(true),
});
const RouteChildren = z.array(
z.object({
label: z.string(),
path: z.string(),
Icon: z.custom<React.ReactNode>(),
end: RouteMatchingEnd,
children: z
.array(
z.object({
label: z.string(),
path: z.string(),
Icon: z.custom<React.ReactNode>(),
end: RouteMatchingEnd,
}),
)
.default([])
.optional(),
}),
);
const RouteSubChild = z.object({
label: z.string(),
path: z.string(),
Icon: z.custom<React.ReactNode>().optional(),
end: RouteMatchingEnd,
renderAction: z.custom<React.ReactNode>().optional(),
});
const RouteChild = z.object({
label: z.string(),
path: z.string(),
Icon: z.custom<React.ReactNode>().optional(),
end: RouteMatchingEnd,
children: z.array(RouteSubChild).default([]).optional(),
collapsible: z.boolean().default(false).optional(),
collapsed: z.boolean().default(false).optional(),
renderAction: z.custom<React.ReactNode>().optional(),
});
const RouteGroup = z.object({
label: z.string(),
collapsible: z.boolean().optional(),
collapsed: z.boolean().optional(),
children: z.array(RouteChild),
renderAction: z.custom<React.ReactNode>().optional(),
});
export const NavigationConfigSchema = z.object({
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
@@ -36,16 +43,5 @@ export const NavigationConfigSchema = z.object({
.default('false')
.optional()
.transform((value) => value === `true`),
routes: z.array(
z.union([
z.object({
label: z.string(),
collapsible: z.boolean().optional(),
collapsed: z.boolean().optional(),
children: RouteChildren,
renderAction: z.custom<React.ReactNode>().optional(),
}),
Divider,
]),
),
routes: z.array(z.union([RouteGroup, Divider])),
});

View File

@@ -329,16 +329,24 @@ export function SidebarNavigation({
collapsed={item.collapsed}
>
{item.children.map((child) => {
return (
<SidebarItem
key={child.path}
end={child.end}
path={child.path}
Icon={child.Icon}
>
<Trans i18nKey={child.label} defaults={child.label} />
</SidebarItem>
);
if ('collapsible' in child && child.collapsible) {
throw new Error(
'Collapsible groups are not supported in the old Sidebar. Please migrate to the new Sidebar.',
);
}
if ('path' in child) {
return (
<SidebarItem
key={child.path}
end={child.end}
path={child.path}
Icon={child.Icon}
>
<Trans i18nKey={child.label} defaults={child.label} />
</SidebarItem>
);
}
})}
</SidebarGroup>
);