Next.js 16, React 19.2, Identities page, Invitations identities step, PNPM Catalogs (#381)
* Upgraded to Next.js 16 * Refactored code to comply with React 19.2 ESLint rules * Refactored some useEffect usages with the new useEffectEvent * Added Identities page and added second step to set up an identity after accepting an invitation * Updated all dependencies * Introduced PNPM catalogs for some frequently updated dependencies * Bugs fixing and improvements
This commit is contained in:
committed by
GitHub
parent
ea0c1dde80
commit
2c0d0bf7a1
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useContext, useId, useRef, useState } from 'react';
|
||||
import { useContext, useId, useState } from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
@@ -43,23 +43,20 @@ export function Sidebar(props: {
|
||||
}) => React.ReactNode);
|
||||
}) {
|
||||
const [collapsed, setCollapsed] = useState(props.collapsed ?? false);
|
||||
const isExpandedRef = useRef<boolean>(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const expandOnHover =
|
||||
props.expandOnHover ??
|
||||
process.env.NEXT_PUBLIC_EXPAND_SIDEBAR_ON_HOVER === 'true';
|
||||
|
||||
const sidebarSizeClassName = getSidebarSizeClassName(
|
||||
collapsed,
|
||||
isExpandedRef.current,
|
||||
);
|
||||
const sidebarSizeClassName = getSidebarSizeClassName(collapsed, isExpanded);
|
||||
|
||||
const className = getClassNameBuilder(
|
||||
cn(props.className ?? '', sidebarSizeClassName, {}),
|
||||
)();
|
||||
|
||||
const containerClassName = cn(sidebarSizeClassName, 'bg-inherit', {
|
||||
'max-w-[4rem]': expandOnHover && isExpandedRef.current,
|
||||
'max-w-[4rem]': expandOnHover && isExpanded,
|
||||
});
|
||||
|
||||
const ctx = { collapsed, setCollapsed };
|
||||
@@ -68,7 +65,7 @@ export function Sidebar(props: {
|
||||
props.collapsed && expandOnHover
|
||||
? () => {
|
||||
setCollapsed(false);
|
||||
isExpandedRef.current = true;
|
||||
setIsExpanded(true);
|
||||
}
|
||||
: undefined;
|
||||
|
||||
@@ -77,11 +74,11 @@ export function Sidebar(props: {
|
||||
? () => {
|
||||
if (!isRadixPopupOpen()) {
|
||||
setCollapsed(true);
|
||||
isExpandedRef.current = false;
|
||||
setIsExpanded(false);
|
||||
} else {
|
||||
onRadixPopupClose(() => {
|
||||
setCollapsed(true);
|
||||
isExpandedRef.current = false;
|
||||
setIsExpanded(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -124,6 +121,66 @@ export function SidebarContent({
|
||||
return <div className={className}>{children}</div>;
|
||||
}
|
||||
|
||||
function SidebarGroupWrapper({
|
||||
id,
|
||||
sidebarCollapsed,
|
||||
collapsible,
|
||||
isGroupCollapsed,
|
||||
setIsGroupCollapsed,
|
||||
label,
|
||||
}: {
|
||||
id: string;
|
||||
sidebarCollapsed: boolean;
|
||||
collapsible: boolean;
|
||||
isGroupCollapsed: boolean;
|
||||
setIsGroupCollapsed: (isGroupCollapsed: boolean) => void;
|
||||
label: React.ReactNode;
|
||||
}) {
|
||||
const className = cn(
|
||||
'px-container group flex items-center justify-between space-x-2.5',
|
||||
{
|
||||
'py-2.5': !sidebarCollapsed,
|
||||
},
|
||||
);
|
||||
|
||||
if (collapsible) {
|
||||
return (
|
||||
<button
|
||||
aria-expanded={!isGroupCollapsed}
|
||||
aria-controls={id}
|
||||
onClick={() => setIsGroupCollapsed(!isGroupCollapsed)}
|
||||
className={className}
|
||||
>
|
||||
<span
|
||||
className={'text-muted-foreground text-xs font-semibold uppercase'}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
|
||||
<If condition={collapsible}>
|
||||
<ChevronDown
|
||||
className={cn(`h-3 transition duration-300`, {
|
||||
'rotate-180': !isGroupCollapsed,
|
||||
})}
|
||||
/>
|
||||
</If>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
if (sidebarCollapsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<span className={'text-muted-foreground text-xs font-semibold uppercase'}>
|
||||
{label}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SidebarGroup({
|
||||
label,
|
||||
collapsed = false,
|
||||
@@ -138,61 +195,20 @@ export function SidebarGroup({
|
||||
const [isGroupCollapsed, setIsGroupCollapsed] = useState(collapsed);
|
||||
const id = useId();
|
||||
|
||||
const Title = (props: React.PropsWithChildren) => {
|
||||
if (sidebarCollapsed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={'text-muted-foreground text-xs font-semibold uppercase'}>
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const Wrapper = () => {
|
||||
const className = cn(
|
||||
'px-container group flex items-center justify-between space-x-2.5',
|
||||
{
|
||||
'py-2.5': !sidebarCollapsed,
|
||||
},
|
||||
);
|
||||
|
||||
if (collapsible) {
|
||||
return (
|
||||
<button
|
||||
aria-expanded={!isGroupCollapsed}
|
||||
aria-controls={id}
|
||||
onClick={() => setIsGroupCollapsed(!isGroupCollapsed)}
|
||||
className={className}
|
||||
>
|
||||
<Title>{label}</Title>
|
||||
|
||||
<If condition={collapsible}>
|
||||
<ChevronDown
|
||||
className={cn(`h-3 transition duration-300`, {
|
||||
'rotate-180': !isGroupCollapsed,
|
||||
})}
|
||||
/>
|
||||
</If>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Title>{label}</Title>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('flex flex-col', {
|
||||
'gap-y-2 py-1': !collapsed,
|
||||
})}
|
||||
>
|
||||
<Wrapper />
|
||||
<SidebarGroupWrapper
|
||||
id={id}
|
||||
sidebarCollapsed={sidebarCollapsed}
|
||||
collapsible={collapsible}
|
||||
isGroupCollapsed={isGroupCollapsed}
|
||||
setIsGroupCollapsed={setIsGroupCollapsed}
|
||||
label={label}
|
||||
/>
|
||||
|
||||
<If condition={collapsible ? !isGroupCollapsed : true}>
|
||||
<div id={id} className={'flex flex-col space-y-1.5'}>
|
||||
|
||||
Reference in New Issue
Block a user