feat: add skeleton loading state to member sidebar

This commit is contained in:
Jannis Braun
2026-03-22 02:44:46 +01:00
parent 02dcd2f903
commit a2ff5cb75d
@@ -48,6 +48,7 @@ export function MemberSidebar() {
const members = useSpaceStore((s) => s.members); const members = useSpaceStore((s) => s.members);
const spaces = useSpaceStore((s) => s.spaces); const spaces = useSpaceStore((s) => s.spaces);
const currentSpaceId = useSpaceStore((s) => s.currentSpaceId); const currentSpaceId = useSpaceStore((s) => s.currentSpaceId);
const loadingSpaceId = useSpaceStore((s) => s.loadingSpaceId);
const memberListOpen = useUIStore((s) => s.memberListOpen); const memberListOpen = useUIStore((s) => s.memberListOpen);
const openUserProfile = useUIStore((s) => s.openUserProfile); const openUserProfile = useUIStore((s) => s.openUserProfile);
const userActivities = useActivityStore((s) => s.userActivities); const userActivities = useActivityStore((s) => s.userActivities);
@@ -79,6 +80,8 @@ export function MemberSidebar() {
if (!memberListOpen) return null; if (!memberListOpen) return null;
const isLoadingSpace = !!loadingSpaceId && loadingSpaceId === currentSpaceId;
const getMemberColor = (member: MemberWithUser): React.CSSProperties | undefined => { const getMemberColor = (member: MemberWithUser): React.CSSProperties | undefined => {
if (member.roles && member.roles.length > 0) { if (member.roles && member.roles.length > 0) {
const sorted = [...member.roles].sort((a, b) => b.position - a.position); const sorted = [...member.roles].sort((a, b) => b.position - a.position);
@@ -148,6 +151,26 @@ export function MemberSidebar() {
return ( return (
<div className="w-60 bg-surface-members flex-shrink-0 overflow-y-auto select-none no-scrollbar hidden md:block border-l border-border-hard"> <div className="w-60 bg-surface-members flex-shrink-0 overflow-y-auto select-none no-scrollbar hidden md:block border-l border-border-hard">
{isLoadingSpace ? (
<div className="px-3 pt-4">
{/* Role group 1 */}
<div className="skeleton skeleton-bar h-2 w-[40%] mb-3" style={{ animationDelay: '0s' }} />
{Array.from({ length: 2 }, (_, i) => (
<div key={i} className="flex items-center gap-3 py-1.5 mb-1" style={{ animationDelay: `${i * 0.12}s` }}>
<div className="skeleton skeleton-circle w-8 h-8 flex-shrink-0" style={{ animationDelay: `${i * 0.12}s` }} />
<div className="skeleton skeleton-bar" style={{ width: `${45 + (i * 19) % 30}%`, animationDelay: `${i * 0.12}s` }} />
</div>
))}
{/* Role group 2 */}
<div className="skeleton skeleton-bar h-2 w-[50%] mb-3 mt-5" style={{ animationDelay: '0.25s' }} />
{Array.from({ length: 5 }, (_, i) => (
<div key={i} className="flex items-center gap-3 py-1.5 mb-1" style={{ animationDelay: `${(i + 2) * 0.12}s` }}>
<div className="skeleton skeleton-circle w-8 h-8 flex-shrink-0" style={{ animationDelay: `${(i + 2) * 0.12}s` }} />
<div className="skeleton skeleton-bar" style={{ width: `${40 + (i * 15) % 35}%`, animationDelay: `${(i + 2) * 0.12}s` }} />
</div>
))}
</div>
) : (
<div className="p-3"> <div className="p-3">
{/* Role-based groups */} {/* Role-based groups */}
{roleGroups.map(([key, group]) => ( {roleGroups.map(([key, group]) => (
@@ -169,6 +192,7 @@ export function MemberSidebar() {
</div> </div>
)} )}
</div> </div>
)}
</div> </div>
); );
} }