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:
committed by
GitHub
parent
27ef8f7510
commit
465655fdd4
@@ -13,7 +13,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.48.2",
|
"@playwright/test": "^1.48.2",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"node-html-parser": "^6.1.13"
|
"node-html-parser": "^6.1.13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ export const metadata = {
|
|||||||
title: `Super Admin`,
|
title: `Super Admin`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
export default function AdminLayout(props: React.PropsWithChildren) {
|
export default function AdminLayout(props: React.PropsWithChildren) {
|
||||||
return (
|
return (
|
||||||
<Page style={'sidebar'}>
|
<Page style={'sidebar'}>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
ConsumerProvidedEventTypes,
|
ConsumerProvidedEventTypes,
|
||||||
useAppEvents,
|
useAppEvents,
|
||||||
} from '@kit/shared/events';
|
} from '@kit/shared/events';
|
||||||
|
import { isBrowser } from '@kit/shared/utils';
|
||||||
|
|
||||||
type AnalyticsMapping<
|
type AnalyticsMapping<
|
||||||
T extends ConsumerProvidedEventTypes = NonNullable<unknown>,
|
T extends ConsumerProvidedEventTypes = NonNullable<unknown>,
|
||||||
@@ -65,10 +66,7 @@ const analyticsMapping: AnalyticsMapping = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
function AnalyticsProviderBrowser(props: React.PropsWithChildren) {
|
||||||
* Provider for the analytics service
|
|
||||||
*/
|
|
||||||
export function AnalyticsProvider(props: React.PropsWithChildren) {
|
|
||||||
// Subscribe to app events and map them to analytics actions
|
// Subscribe to app events and map them to analytics actions
|
||||||
useAnalyticsMapping(analyticsMapping);
|
useAnalyticsMapping(analyticsMapping);
|
||||||
|
|
||||||
@@ -79,6 +77,17 @@ export function AnalyticsProvider(props: React.PropsWithChildren) {
|
|||||||
return props.children;
|
return props.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for the analytics service
|
||||||
|
*/
|
||||||
|
export function AnalyticsProvider(props: React.PropsWithChildren) {
|
||||||
|
if (!isBrowser()) {
|
||||||
|
return props.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <AnalyticsProviderBrowser>{props.children}</AnalyticsProviderBrowser>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to report page views to the analytics service
|
* Hook to report page views to the analytics service
|
||||||
* @param reportAnalyticsFn
|
* @param reportAnalyticsFn
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@next/bundle-analyzer": "15.0.2",
|
"@next/bundle-analyzer": "15.0.2",
|
||||||
"@types/mdx": "^2.0.13",
|
"@types/mdx": "^2.0.13",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||||
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
"@types/react-dom": "npm:types-react-dom@19.0.0-rc.1",
|
||||||
"i18next": "23.16.4",
|
"i18next": "23.16.4",
|
||||||
"react-i18next": "15.1.0"
|
"react-i18next": "^15.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tailwind-config": "workspace:*",
|
"@kit/tailwind-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/node": "^22.8.6"
|
"@types/node": "^22.8.7"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/wordpress": "workspace:*",
|
"@kit/wordpress": "workspace:*",
|
||||||
"@types/node": "^22.8.6"
|
"@types/node": "^22.8.7"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"root": true,
|
"root": true,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||||
"react": "19.0.0-rc-45804af1-20241021",
|
"react": "19.0.0-rc-45804af1-20241021",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"@types/react": "npm:types-react@19.0.0-rc.1",
|
"@types/react": "npm:types-react@19.0.0-rc.1",
|
||||||
"wp-types": "^4.66.1"
|
"wp-types": "^4.66.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,26 +15,52 @@ export async function initializeServerI18n(
|
|||||||
const i18nInstance = createInstance();
|
const i18nInstance = createInstance();
|
||||||
const loadedNamespaces = new Set<string>();
|
const loadedNamespaces = new Set<string>();
|
||||||
|
|
||||||
await i18nInstance
|
await new Promise((resolve) => {
|
||||||
.use(
|
void i18nInstance
|
||||||
resourcesToBackend(async (language, namespace, callback) => {
|
.use(
|
||||||
try {
|
resourcesToBackend(async (language, namespace, callback) => {
|
||||||
const data = await resolver(language, namespace);
|
try {
|
||||||
loadedNamespaces.add(namespace);
|
const data = await resolver(language, namespace);
|
||||||
|
loadedNamespaces.add(namespace);
|
||||||
|
|
||||||
return callback(null, data);
|
return callback(null, data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(
|
console.log(
|
||||||
`Error loading i18n file: locales/${language}/${namespace}.json`,
|
`Error loading i18n file: locales/${language}/${namespace}.json`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
|
|
||||||
return callback(null, {});
|
return callback(null, {});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.use(initReactI18next)
|
.use({
|
||||||
.init(settings);
|
type: '3rdParty',
|
||||||
|
init: async (i18next: typeof i18nInstance) => {
|
||||||
|
let iterations = 0;
|
||||||
|
const maxIterations = 100;
|
||||||
|
|
||||||
|
// do not bind this to the i18next instance until it's initialized
|
||||||
|
while (i18next.isInitializing) {
|
||||||
|
iterations++;
|
||||||
|
|
||||||
|
if (iterations > maxIterations) {
|
||||||
|
console.error(
|
||||||
|
`i18next is not initialized after ${maxIterations} iterations`,
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
initReactI18next.init(i18next);
|
||||||
|
resolve(i18next);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.init(settings);
|
||||||
|
});
|
||||||
|
|
||||||
const namespaces = settings.ns as string[];
|
const namespaces = settings.ns as string[];
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"@kit/resend": "workspace:*",
|
"@kit/resend": "workspace:*",
|
||||||
"@kit/tailwind-config": "workspace:*",
|
"@kit/tailwind-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tailwind-config": "workspace:*",
|
"@kit/tailwind-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/node": "^22.8.6",
|
"@types/node": "^22.8.7",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ import { useSupabase } from './use-supabase';
|
|||||||
*/
|
*/
|
||||||
const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password'];
|
const PRIVATE_PATH_PREFIXES = ['/home', '/admin', '/join', '/update-password'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name AUTH_PATHS
|
||||||
|
* @description A list of auth paths
|
||||||
|
*/
|
||||||
|
const AUTH_PATHS = ['/auth'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name useAuthChangeListener
|
* @name useAuthChangeListener
|
||||||
* @param privatePathPrefixes - A list of private path prefixes
|
* @param privatePathPrefixes - A list of private path prefixes
|
||||||
@@ -53,6 +59,12 @@ export function useAuthChangeListener({
|
|||||||
|
|
||||||
// revalidate user session when user signs in or out
|
// revalidate user session when user signs in or out
|
||||||
if (event === 'SIGNED_OUT') {
|
if (event === 'SIGNED_OUT') {
|
||||||
|
// sometimes Supabase sends SIGNED_OUT event
|
||||||
|
// but in the auth path, so we ignore it
|
||||||
|
if (AUTH_PATHS.some((path) => pathName.startsWith(path))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
import {
|
import {
|
||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import type {
|
import type {
|
||||||
@@ -45,6 +46,8 @@ interface ReactTableProps<T extends object> {
|
|||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
pageCount?: number;
|
pageCount?: number;
|
||||||
onPaginationChange?: (pagination: PaginationState) => void;
|
onPaginationChange?: (pagination: PaginationState) => void;
|
||||||
|
manualPagination?: boolean;
|
||||||
|
manualSorting?: boolean;
|
||||||
tableProps?: React.ComponentProps<typeof Table> &
|
tableProps?: React.ComponentProps<typeof Table> &
|
||||||
Record<`data-${string}`, string>;
|
Record<`data-${string}`, string>;
|
||||||
}
|
}
|
||||||
@@ -57,6 +60,8 @@ export function DataTable<T extends object>({
|
|||||||
pageCount,
|
pageCount,
|
||||||
onPaginationChange,
|
onPaginationChange,
|
||||||
tableProps,
|
tableProps,
|
||||||
|
manualPagination = true,
|
||||||
|
manualSorting = false,
|
||||||
}: ReactTableProps<T>) {
|
}: ReactTableProps<T>) {
|
||||||
const [pagination, setPagination] = useState<PaginationState>({
|
const [pagination, setPagination] = useState<PaginationState>({
|
||||||
pageIndex: pageIndex ?? 0,
|
pageIndex: pageIndex ?? 0,
|
||||||
@@ -74,7 +79,9 @@ export function DataTable<T extends object>({
|
|||||||
data,
|
data,
|
||||||
columns,
|
columns,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
manualPagination: true,
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
manualPagination,
|
||||||
|
manualSorting,
|
||||||
onSortingChange: setSorting,
|
onSortingChange: setSorting,
|
||||||
onColumnFiltersChange: setColumnFilters,
|
onColumnFiltersChange: setColumnFilters,
|
||||||
onColumnVisibilityChange: setColumnVisibility,
|
onColumnVisibilityChange: setColumnVisibility,
|
||||||
|
|||||||
@@ -9,25 +9,32 @@ const Divider = z.object({
|
|||||||
divider: z.literal(true),
|
divider: z.literal(true),
|
||||||
});
|
});
|
||||||
|
|
||||||
const RouteChildren = z.array(
|
const RouteSubChild = z.object({
|
||||||
z.object({
|
label: z.string(),
|
||||||
label: z.string(),
|
path: z.string(),
|
||||||
path: z.string(),
|
Icon: z.custom<React.ReactNode>().optional(),
|
||||||
Icon: z.custom<React.ReactNode>(),
|
end: RouteMatchingEnd,
|
||||||
end: RouteMatchingEnd,
|
renderAction: z.custom<React.ReactNode>().optional(),
|
||||||
children: z
|
});
|
||||||
.array(
|
|
||||||
z.object({
|
const RouteChild = z.object({
|
||||||
label: z.string(),
|
label: z.string(),
|
||||||
path: z.string(),
|
path: z.string(),
|
||||||
Icon: z.custom<React.ReactNode>(),
|
Icon: z.custom<React.ReactNode>().optional(),
|
||||||
end: RouteMatchingEnd,
|
end: RouteMatchingEnd,
|
||||||
}),
|
children: z.array(RouteSubChild).default([]).optional(),
|
||||||
)
|
collapsible: z.boolean().default(false).optional(),
|
||||||
.default([])
|
collapsed: z.boolean().default(false).optional(),
|
||||||
.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({
|
export const NavigationConfigSchema = z.object({
|
||||||
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
|
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
|
||||||
@@ -36,16 +43,5 @@ export const NavigationConfigSchema = z.object({
|
|||||||
.default('false')
|
.default('false')
|
||||||
.optional()
|
.optional()
|
||||||
.transform((value) => value === `true`),
|
.transform((value) => value === `true`),
|
||||||
routes: z.array(
|
routes: z.array(z.union([RouteGroup, Divider])),
|
||||||
z.union([
|
|
||||||
z.object({
|
|
||||||
label: z.string(),
|
|
||||||
collapsible: z.boolean().optional(),
|
|
||||||
collapsed: z.boolean().optional(),
|
|
||||||
children: RouteChildren,
|
|
||||||
renderAction: z.custom<React.ReactNode>().optional(),
|
|
||||||
}),
|
|
||||||
Divider,
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -329,16 +329,24 @@ export function SidebarNavigation({
|
|||||||
collapsed={item.collapsed}
|
collapsed={item.collapsed}
|
||||||
>
|
>
|
||||||
{item.children.map((child) => {
|
{item.children.map((child) => {
|
||||||
return (
|
if ('collapsible' in child && child.collapsible) {
|
||||||
<SidebarItem
|
throw new Error(
|
||||||
key={child.path}
|
'Collapsible groups are not supported in the old Sidebar. Please migrate to the new Sidebar.',
|
||||||
end={child.end}
|
);
|
||||||
path={child.path}
|
}
|
||||||
Icon={child.Icon}
|
|
||||||
>
|
if ('path' in child) {
|
||||||
<Trans i18nKey={child.label} defaults={child.label} />
|
return (
|
||||||
</SidebarItem>
|
<SidebarItem
|
||||||
);
|
key={child.path}
|
||||||
|
end={child.end}
|
||||||
|
path={child.path}
|
||||||
|
Icon={child.Icon}
|
||||||
|
>
|
||||||
|
<Trans i18nKey={child.label} defaults={child.label} />
|
||||||
|
</SidebarItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
})}
|
})}
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -910,18 +910,96 @@ export function SidebarNavigation({
|
|||||||
</SidebarGroupAction>
|
</SidebarGroupAction>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
<ContentContainer>
|
<SidebarGroupContent>
|
||||||
<SidebarGroupContent>
|
<SidebarMenu>
|
||||||
<SidebarMenu>
|
<ContentContainer>
|
||||||
{item.children.map((child) => {
|
{item.children.map((child, childIndex) => {
|
||||||
const isActive = isRouteActive(
|
if (child.renderAction) {
|
||||||
child.path,
|
return (
|
||||||
currentPath,
|
<SidebarMenuSubItem key={child.path}>
|
||||||
child.end,
|
{child.renderAction}
|
||||||
);
|
</SidebarMenuSubItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
const Container = (props: React.PropsWithChildren) => {
|
||||||
<SidebarMenuItem key={child.path}>
|
if ('collapsible' in child && child.collapsible) {
|
||||||
|
return (
|
||||||
|
<Collapsible
|
||||||
|
defaultOpen={!child.collapsed}
|
||||||
|
className={'group/collapsible'}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Collapsible>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.children;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ContentContainer = (
|
||||||
|
props: React.PropsWithChildren,
|
||||||
|
) => {
|
||||||
|
if ('collapsible' in child && child.collapsible) {
|
||||||
|
return (
|
||||||
|
<CollapsibleContent>
|
||||||
|
{props.children}
|
||||||
|
</CollapsibleContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.children;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TriggerItem = () => {
|
||||||
|
if ('collapsible' in child && child.collapsible) {
|
||||||
|
return (
|
||||||
|
<CollapsibleTrigger asChild>
|
||||||
|
<SidebarMenuButton tooltip={child.label}>
|
||||||
|
<div
|
||||||
|
className={cn('flex items-center gap-2', {
|
||||||
|
'mx-auto w-full gap-0 [&>svg]:flex-1 [&>svg]:shrink-0':
|
||||||
|
minimized,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{child.Icon}
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'w-auto transition-opacity duration-300',
|
||||||
|
{
|
||||||
|
'w-0 opacity-0': minimized,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Trans
|
||||||
|
i18nKey={child.label}
|
||||||
|
defaults={child.label}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<ChevronDown
|
||||||
|
className={cn(
|
||||||
|
'ml-auto size-4 transition-transform group-data-[state=open]/collapsible:rotate-180',
|
||||||
|
{
|
||||||
|
'hidden size-0': minimized,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = 'path' in child ? child.path : '';
|
||||||
|
const end = 'end' in child ? child.end : false;
|
||||||
|
|
||||||
|
const isActive = isRouteActive(
|
||||||
|
path,
|
||||||
|
currentPath,
|
||||||
|
end,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
<SidebarMenuButton
|
<SidebarMenuButton
|
||||||
asChild
|
asChild
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
@@ -932,10 +1010,9 @@ export function SidebarNavigation({
|
|||||||
'mx-auto w-full !gap-0 [&>svg]:flex-1':
|
'mx-auto w-full !gap-0 [&>svg]:flex-1':
|
||||||
minimized,
|
minimized,
|
||||||
})}
|
})}
|
||||||
href={child.path}
|
href={path}
|
||||||
>
|
>
|
||||||
{child.Icon}
|
{child.Icon}
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-auto transition-opacity duration-300',
|
'w-auto transition-opacity duration-300',
|
||||||
@@ -951,61 +1028,86 @@ export function SidebarNavigation({
|
|||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</SidebarMenuButton>
|
</SidebarMenuButton>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
<If condition={child.children}>
|
return (
|
||||||
{(children) => (
|
<Container key={`group-${index}-${childIndex}`}>
|
||||||
<SidebarMenuSub
|
<SidebarMenuItem>
|
||||||
className={cn({ 'mx-0 px-1.5': minimized })}
|
<TriggerItem />
|
||||||
>
|
|
||||||
{children.map((child) => {
|
|
||||||
const isActive = isRouteActive(
|
|
||||||
child.path,
|
|
||||||
currentPath,
|
|
||||||
child.end,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
<ContentContainer>
|
||||||
<SidebarMenuSubItem key={child.path}>
|
<If condition={child.children}>
|
||||||
<SidebarMenuSubButton
|
{(children) => (
|
||||||
isActive={isActive}
|
<SidebarMenuSub
|
||||||
asChild
|
className={cn({
|
||||||
>
|
'mx-0 px-1.5': minimized,
|
||||||
<Link
|
})}
|
||||||
className={cn('flex items-center', {
|
>
|
||||||
'mx-auto w-full !gap-0 [&>svg]:flex-1':
|
{children.map((child) => {
|
||||||
minimized,
|
if (child.renderAction) {
|
||||||
})}
|
return (
|
||||||
href={child.path}
|
<SidebarMenuSubItem
|
||||||
>
|
key={child.path}
|
||||||
{child.Icon}
|
|
||||||
|
|
||||||
<span
|
|
||||||
className={cn(
|
|
||||||
'w-auto transition-opacity duration-300',
|
|
||||||
{
|
|
||||||
'w-0 opacity-0': minimized,
|
|
||||||
},
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<Trans
|
{child.renderAction}
|
||||||
i18nKey={child.label}
|
</SidebarMenuSubItem>
|
||||||
defaults={child.label}
|
);
|
||||||
/>
|
}
|
||||||
</span>
|
|
||||||
</Link>
|
const isActive = isRouteActive(
|
||||||
</SidebarMenuSubButton>
|
child.path,
|
||||||
</SidebarMenuSubItem>
|
currentPath,
|
||||||
);
|
child.end,
|
||||||
})}
|
);
|
||||||
</SidebarMenuSub>
|
|
||||||
)}
|
return (
|
||||||
</If>
|
<SidebarMenuSubItem key={child.path}>
|
||||||
</SidebarMenuItem>
|
<SidebarMenuSubButton
|
||||||
|
isActive={isActive}
|
||||||
|
asChild
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
className={cn(
|
||||||
|
'flex items-center',
|
||||||
|
{
|
||||||
|
'mx-auto w-full !gap-0 [&>svg]:flex-1':
|
||||||
|
minimized,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
href={child.path}
|
||||||
|
>
|
||||||
|
{child.Icon}
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'w-auto transition-opacity duration-300',
|
||||||
|
{
|
||||||
|
'w-0 opacity-0':
|
||||||
|
minimized,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Trans
|
||||||
|
i18nKey={child.label}
|
||||||
|
defaults={child.label}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
</SidebarMenuSubButton>
|
||||||
|
</SidebarMenuSubItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</SidebarMenuSub>
|
||||||
|
)}
|
||||||
|
</If>
|
||||||
|
</ContentContainer>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</SidebarMenu>
|
</ContentContainer>
|
||||||
</SidebarGroupContent>
|
</SidebarMenu>
|
||||||
</ContentContainer>
|
</SidebarGroupContent>
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
|
|
||||||
<If condition={minimized && !isLast}>
|
<If condition={minimized && !isLast}>
|
||||||
|
|||||||
48
pnpm-lock.yaml
generated
48
pnpm-lock.yaml
generated
@@ -11,7 +11,7 @@ overrides:
|
|||||||
'@types/react': npm:types-react@19.0.0-rc.1
|
'@types/react': npm:types-react@19.0.0-rc.1
|
||||||
'@types/react-dom': npm:types-react-dom@19.0.0-rc.1
|
'@types/react-dom': npm:types-react-dom@19.0.0-rc.1
|
||||||
i18next: 23.16.4
|
i18next: 23.16.4
|
||||||
react-i18next: 15.1.0
|
react-i18next: ^15.1.0
|
||||||
|
|
||||||
importers:
|
importers:
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ importers:
|
|||||||
specifier: ^1.48.2
|
specifier: ^1.48.2
|
||||||
version: 1.48.2
|
version: 1.48.2
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
node-html-parser:
|
node-html-parser:
|
||||||
specifier: ^6.1.13
|
specifier: ^6.1.13
|
||||||
@@ -156,7 +156,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
recharts:
|
recharts:
|
||||||
specifier: 2.13.3
|
specifier: 2.13.3
|
||||||
@@ -190,7 +190,7 @@ importers:
|
|||||||
specifier: ^2.0.13
|
specifier: ^2.0.13
|
||||||
version: 2.0.13
|
version: 2.0.13
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: npm:types-react@19.0.0-rc.1
|
specifier: npm:types-react@19.0.0-rc.1
|
||||||
@@ -247,7 +247,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../tooling/typescript
|
version: link:../../tooling/typescript
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
|
|
||||||
packages/billing/core:
|
packages/billing/core:
|
||||||
@@ -331,7 +331,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.23.8
|
specifier: ^3.23.8
|
||||||
@@ -453,7 +453,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../wordpress
|
version: link:../wordpress
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
|
|
||||||
packages/cms/keystatic:
|
packages/cms/keystatic:
|
||||||
@@ -484,7 +484,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: npm:types-react@19.0.0-rc.1
|
specifier: npm:types-react@19.0.0-rc.1
|
||||||
@@ -526,7 +526,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: npm:types-react@19.0.0-rc.1
|
specifier: npm:types-react@19.0.0-rc.1
|
||||||
@@ -675,7 +675,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^1.7.0
|
specifier: ^1.7.0
|
||||||
@@ -801,7 +801,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^1.7.0
|
specifier: ^1.7.0
|
||||||
@@ -849,7 +849,7 @@ importers:
|
|||||||
specifier: 19.0.0-rc-45804af1-20241021
|
specifier: 19.0.0-rc-45804af1-20241021
|
||||||
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
|
|
||||||
packages/features/team-accounts:
|
packages/features/team-accounts:
|
||||||
@@ -937,7 +937,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^1.7.0
|
specifier: ^1.7.0
|
||||||
@@ -986,7 +986,7 @@ importers:
|
|||||||
specifier: 19.0.0-rc-45804af1-20241021
|
specifier: 19.0.0-rc-45804af1-20241021
|
||||||
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
version: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
|
|
||||||
packages/mailers/core:
|
packages/mailers/core:
|
||||||
@@ -1010,7 +1010,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../tooling/typescript
|
version: link:../../../tooling/typescript
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.23.8
|
specifier: ^3.23.8
|
||||||
@@ -1062,7 +1062,7 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../tooling/typescript
|
version: link:../../../tooling/typescript
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.8.6
|
specifier: ^22.8.7
|
||||||
version: 22.9.0
|
version: 22.9.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.23.8
|
specifier: ^3.23.8
|
||||||
@@ -1429,7 +1429,7 @@ importers:
|
|||||||
specifier: ^7.53.1
|
specifier: ^7.53.1
|
||||||
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
version: 7.53.1(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 15.1.0
|
specifier: ^15.1.0
|
||||||
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 15.1.0(i18next@23.16.4)(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
sonner:
|
sonner:
|
||||||
specifier: ^1.7.0
|
specifier: ^1.7.0
|
||||||
@@ -6680,8 +6680,8 @@ packages:
|
|||||||
react-native:
|
react-native:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
react-is@19.0.0-rc-4d577fd2-20241104:
|
react-is@19.0.0-rc-33c7bd9a-20241104:
|
||||||
resolution: {integrity: sha512-U52Z3ZQsfvw6cIbCUt+JAPn73TL+4hN4X5D9JvQ3M+M3nlibKXL1SwC90yD23TI2gsZghM+OFXW561pMpS+6yg==}
|
resolution: {integrity: sha512-MNHzi8NhHjNzoO4ADF2VMuEkaWX6qJNz+/J6CoHsKVhA7LBAO20oGe87FB2f/0gmtOldH9g7rW9nyaEo/NJjBg==}
|
||||||
|
|
||||||
react-promise-suspense@0.3.4:
|
react-promise-suspense@0.3.4:
|
||||||
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
|
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
|
||||||
@@ -12616,7 +12616,7 @@ snapshots:
|
|||||||
|
|
||||||
hoist-non-react-statics@3.3.2:
|
hoist-non-react-statics@3.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
react-is: 19.0.0-rc-4d577fd2-20241104
|
react-is: 19.0.0-rc-33c7bd9a-20241104
|
||||||
|
|
||||||
html-escaper@2.0.2: {}
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
@@ -13993,7 +13993,7 @@ snapshots:
|
|||||||
'@jest/types': 24.9.0
|
'@jest/types': 24.9.0
|
||||||
ansi-regex: 4.1.1
|
ansi-regex: 4.1.1
|
||||||
ansi-styles: 3.2.1
|
ansi-styles: 3.2.1
|
||||||
react-is: 19.0.0-rc-4d577fd2-20241104
|
react-is: 19.0.0-rc-33c7bd9a-20241104
|
||||||
|
|
||||||
prismjs@1.29.0: {}
|
prismjs@1.29.0: {}
|
||||||
|
|
||||||
@@ -14009,7 +14009,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
react-is: 19.0.0-rc-4d577fd2-20241104
|
react-is: 19.0.0-rc-33c7bd9a-20241104
|
||||||
|
|
||||||
prosemirror-commands@1.6.2:
|
prosemirror-commands@1.6.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -14143,7 +14143,7 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
||||||
|
|
||||||
react-is@19.0.0-rc-4d577fd2-20241104: {}
|
react-is@19.0.0-rc-33c7bd9a-20241104: {}
|
||||||
|
|
||||||
react-promise-suspense@0.3.4:
|
react-promise-suspense@0.3.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -14237,7 +14237,7 @@ snapshots:
|
|||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
react: 19.0.0-rc-45804af1-20241021
|
react: 19.0.0-rc-45804af1-20241021
|
||||||
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
react-dom: 19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021)
|
||||||
react-is: 19.0.0-rc-4d577fd2-20241104
|
react-is: 19.0.0-rc-33c7bd9a-20241104
|
||||||
react-smooth: 4.0.1(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
react-smooth: 4.0.1(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
recharts-scale: 0.4.5
|
recharts-scale: 0.4.5
|
||||||
tiny-invariant: 1.3.3
|
tiny-invariant: 1.3.3
|
||||||
|
|||||||
Reference in New Issue
Block a user