diff --git a/src/app/styles/animations.scss b/src/app/styles/animations.scss
index 0c64494..99104e0 100644
--- a/src/app/styles/animations.scss
+++ b/src/app/styles/animations.scss
@@ -66,3 +66,31 @@
}
}
}
+
+.collapsible-content {
+ overflow: hidden;
+}
+.collapsible-content[data-state='open'] {
+ animation: slideDown 300ms ease-out;
+}
+.collapsible-content[data-state='closed'] {
+ animation: slideUp 300ms ease-out;
+}
+
+@keyframes slideDown {
+ from {
+ height: 0;
+ }
+ to {
+ height: var(--radix-collapsible-content-height);
+ }
+}
+
+@keyframes slideUp {
+ from {
+ height: var(--radix-collapsible-content-height);
+ }
+ to {
+ height: 0;
+ }
+}
diff --git a/src/shared/ui/sidebar/Sidebar.tsx b/src/shared/ui/sidebar/Sidebar.tsx
index 3069e61..60af193 100644
--- a/src/shared/ui/sidebar/Sidebar.tsx
+++ b/src/shared/ui/sidebar/Sidebar.tsx
@@ -629,7 +629,7 @@ function SidebarMenuSubButton({
data-size={size}
data-active={isActive}
className={cn(
- 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden group-data-[collapsible=icon]:hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden group-data-[collapsible=icon]:hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[size=md]:text-sm data-[size=sm]:text-xs [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
className
)}
{...props}
diff --git a/src/widgets/app-sidebar/config/sidebar.ts b/src/widgets/app-sidebar/config/sidebar.ts
new file mode 100644
index 0000000..7652ac1
--- /dev/null
+++ b/src/widgets/app-sidebar/config/sidebar.ts
@@ -0,0 +1,13 @@
+import { Mail, Settings, ShieldUser, UsersRound } from 'lucide-react';
+import { routes } from 'shared/config';
+
+export const team = [
+ {
+ url: routes.team.members(),
+ title: 'Участники',
+ icon: UsersRound,
+ },
+ { url: routes.team.invitations(), title: 'Приглашения', icon: Mail },
+ { url: routes.team.roles(), title: 'Роли', icon: ShieldUser },
+ { url: routes.team.settings(), title: 'Настройки', icon: Settings },
+] as const;
diff --git a/src/widgets/app-sidebar/ui/AppSidebar.tsx b/src/widgets/app-sidebar/ui/AppSidebar.tsx
index 5d0c81a..5094de9 100644
--- a/src/widgets/app-sidebar/ui/AppSidebar.tsx
+++ b/src/widgets/app-sidebar/ui/AppSidebar.tsx
@@ -1,46 +1,16 @@
-'use client';
-
-import { InviteTeamMemberDialog } from 'features/teams/invite';
-import { ChevronRight, SquarePlusIcon, UserRound, UsersRound } from 'lucide-react';
-import Link from 'next/link';
-import { routes } from 'shared/config';
import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger,
Separator,
Sidebar,
SidebarContent,
- SidebarFooter,
SidebarGroup,
SidebarHeader,
SidebarMenu,
- SidebarMenuAction,
- SidebarMenuButton,
- SidebarMenuItem,
- SidebarMenuSub,
- SidebarMenuSubButton,
- SidebarMenuSubItem,
SidebarRail,
} from 'shared/ui';
-import { NavUser } from './NavUser';
import { TeamsDropdown } from './teams/TeamsDropdown';
import { Projects } from './Projects';
-
-const team = [
- {
- url: routes.team.members(),
- title: 'Участники',
- action: (
-
-
-
- ),
- },
- { url: routes.team.invitations(), title: 'Приглашения', action: null },
- { url: routes.team.roles(), title: 'Роли', action: null },
- { url: routes.team.settings(), title: 'Настройки', action: null },
-];
+import { MyTeams } from './MyTeams';
+import { Team } from './Team';
export function AppSidebar({ ...props }: Omit, 'children'>) {
return (
@@ -51,49 +21,13 @@ export function AppSidebar({ ...props }: Omit
-
-
-
-
- Мой профиль
-
-
-
-
-
-
-
-
- Команда
-
-
-
-
-
- {team.map((subItem) => (
-
-
-
- {subItem.title}
-
-
- {subItem.action ? (
- {subItem.action}
- ) : null}
-
- ))}
-
-
-
-
+
+
-
-
-
);
diff --git a/src/widgets/app-sidebar/ui/MyTeams.tsx b/src/widgets/app-sidebar/ui/MyTeams.tsx
new file mode 100644
index 0000000..1423db5
--- /dev/null
+++ b/src/widgets/app-sidebar/ui/MyTeams.tsx
@@ -0,0 +1,24 @@
+'use client';
+import { Network } from 'lucide-react';
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { routes } from 'shared/config';
+import { SidebarMenuButton, SidebarMenuItem } from 'shared/ui';
+
+export function MyTeams() {
+ const pathname = usePathname();
+ return (
+
+
+
+
+ Мои команды
+
+
+
+ );
+}
diff --git a/src/widgets/app-sidebar/ui/Projects.tsx b/src/widgets/app-sidebar/ui/Projects.tsx
index 2a13373..653a3be 100644
--- a/src/widgets/app-sidebar/ui/Projects.tsx
+++ b/src/widgets/app-sidebar/ui/Projects.tsx
@@ -6,8 +6,9 @@ import { useTeamStore } from 'entities/team';
import { ArchiveProjectDialog, RestoreProjectDialog } from 'features/projects/archive';
import { CreateProjectDialog } from 'features/projects/create';
import { ShareProjectDialog } from 'features/projects/share';
-import { Archive, Link2, MoreHorizontal, Plus } from 'lucide-react';
+import { Archive, BriefcaseBusiness, Link2, MoreHorizontal, Plus } from 'lucide-react';
import Link from 'next/link';
+import { usePathname } from 'next/navigation';
import { useState } from 'react';
import { routes } from 'shared/config';
import {
@@ -16,7 +17,6 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
SidebarGroup,
- SidebarGroupAction,
SidebarGroupLabel,
SidebarMenu,
SidebarMenuAction,
@@ -28,8 +28,11 @@ import {
export function Projects() {
const slug = useTeamStore.use.slug();
const { isMobile } = useSidebar();
+ const pathname = usePathname();
const [createProjectOpen, setCreateProjectOpen] = useState(false);
const projects = useQuery({ ...ProjectQueries.getProjects(slug!), enabled: !!slug });
+ const projectList = projects.data?.items.slice(0, 6) ?? [];
+ const totalProjects = projects.data?.items.length ?? 0;
if (!projects.data) {
return null;
@@ -39,20 +42,13 @@ export function Projects() {
<>
Проекты
- setCreateProjectOpen(true)}
- >
-
-
- {projects.data.items.map((project) => {
+ {projectList.map((project) => {
const canManage = Boolean(slug && project.canEdit);
return (
-
+
{projectIconCodeToEmoji(project.icon)}
{project.name}
@@ -117,12 +113,25 @@ export function Projects() {
);
})}
-
-
-
- Больше
-
-
+
+
+
+ Все проекты {!!totalProjects && `(${totalProjects})`}
+
+
+
+
+ setCreateProjectOpen(true)}
+ tooltip={'Добавить проект'}
+ >
+
+ Добавить проект
+
diff --git a/src/widgets/app-sidebar/ui/Team.tsx b/src/widgets/app-sidebar/ui/Team.tsx
new file mode 100644
index 0000000..593a39e
--- /dev/null
+++ b/src/widgets/app-sidebar/ui/Team.tsx
@@ -0,0 +1,72 @@
+'use client';
+import { InviteTeamMemberDialog } from 'features/teams/invite';
+import { UsersRound, ChevronRight, Plus } from 'lucide-react';
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import { routes } from 'shared/config';
+import {
+ Collapsible,
+ CollapsibleContent,
+ CollapsibleTrigger,
+ SidebarMenuButton,
+ SidebarMenuItem,
+ SidebarMenuSub,
+ SidebarMenuSubButton,
+ SidebarMenuSubItem,
+ useSidebar,
+} from 'shared/ui';
+import { team } from '../config/sidebar';
+import { useRouter } from 'next/navigation';
+
+export function Team() {
+ const pathname = usePathname();
+ const router = useRouter();
+ const { open, isMobile } = useSidebar();
+
+ const isAllowedToHighlight = !open && !isMobile;
+
+ const handleClickTrigger = () => {
+ if (isAllowedToHighlight) {
+ router.push(routes.team.members());
+ }
+ };
+ return (
+
+
+
+
+
+ Команда
+
+
+
+
+
+ {team.map((subItem) => (
+
+
+
+
+ {subItem.title}
+
+
+
+ ))}
+
+
+
+
+ Пригласить участника
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/app-sidebar/ui/teams/TeamsDropdown.tsx b/src/widgets/app-sidebar/ui/teams/TeamsDropdown.tsx
index f1de64c..f972c42 100644
--- a/src/widgets/app-sidebar/ui/teams/TeamsDropdown.tsx
+++ b/src/widgets/app-sidebar/ui/teams/TeamsDropdown.tsx
@@ -1,7 +1,6 @@
+'use client';
import { CreateTeamDialog } from 'features/teams/create';
-import { Plus } from 'lucide-react';
import Link from 'next/link';
-import { useState } from 'react';
import { routes } from 'shared/config';
import {
DropdownMenu,
@@ -12,18 +11,19 @@ import {
DropdownMenuShortcut,
DropdownMenuTrigger,
SidebarMenuButton,
- useSidebar,
} from 'shared/ui';
import { useTeamsDropdown } from '../../model/useTeamsDropdown';
import { TeamItem } from './TeamItem';
import { TeamTrigger } from './TeamTrigger';
+import { useIsMobile } from 'shared/lib/hooks';
+import { Plus } from 'lucide-react';
+import { useState } from 'react';
export function TeamsDropdown() {
- const { isMobile } = useSidebar();
- const [createTeamOpen, setCreateTeamOpen] = useState(false);
const { open, setOpen, query, visibleTeams, teams, hasMoreTeams, switchTeam } =
useTeamsDropdown();
-
+ const isMobile = useIsMobile();
+ const [createTeamOpen, setCreateTeamOpen] = useState(false);
return (
<>