feat: update sidebar ui
This commit is contained in:
@@ -8,6 +8,7 @@ import * as React from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
ArrowUpRight,
|
||||
BarChart3,
|
||||
BookmarkCheck,
|
||||
Building2,
|
||||
@@ -128,19 +129,12 @@ interface HelpItem {
|
||||
action?: () => void;
|
||||
}
|
||||
|
||||
interface SupportLink {
|
||||
title: string;
|
||||
icon: LucideIcon;
|
||||
href: string;
|
||||
external?: boolean;
|
||||
}
|
||||
|
||||
const TRAINING_STEPS: TrainingStep[] = [
|
||||
{
|
||||
id: "dashboard",
|
||||
title: "Главная панель",
|
||||
description:
|
||||
"Это стартовая точка: отсюда видно общее состояние закупок, статус проектов и свежие уведомления. Сюда возвращаемся, чтобы понять, что делать дальше и какие задачи горят.",
|
||||
"Это стартовая точка: отсюда видно общее состояние закупов, статус проектов и свежие уведомления. Сюда возвращаемся, чтобы понять, что делать дальше и какие задачи горят.",
|
||||
navItemTitle: "Главная",
|
||||
icon: LayoutDashboard,
|
||||
sections: [
|
||||
@@ -509,53 +503,50 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
}, [isTrainingOpen, currentTrainingStep]);
|
||||
const isTrainingVisible = isTrainingOpen && Boolean(currentTrainingStep);
|
||||
|
||||
const supportLinks = React.useMemo<SupportLink[]>(
|
||||
const channelLink = React.useMemo<SupportLink>(
|
||||
() => ({
|
||||
title: "Наш канал",
|
||||
href: "https://t.me/+xqHlRelJ2etkMGIy",
|
||||
icon: Megaphone,
|
||||
external: true,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const helpSubItems = React.useMemo<HelpItem[]>(
|
||||
() => [
|
||||
{
|
||||
title: "Наш канал",
|
||||
href: "https://t.me/+xqHlRelJ2etkMGIy",
|
||||
icon: Megaphone,
|
||||
external: true,
|
||||
},
|
||||
{
|
||||
title: "Поддержка",
|
||||
description: "Свяжитесь с нашей службой поддержки.",
|
||||
href: "https://t.me/smartpost_help_bot",
|
||||
icon: MessageCircle,
|
||||
external: true,
|
||||
},
|
||||
{
|
||||
title: "База знаний",
|
||||
description: "Документация и инструкции по использованию.",
|
||||
href: "https://docs.smartpost.ru",
|
||||
icon: BookOpen,
|
||||
external: true,
|
||||
},
|
||||
{
|
||||
title: "Демо аккаунт",
|
||||
description: "Посмотрите пример рабочего пространства.",
|
||||
href: buildRoute.dashboard(DEMO_WORKSPACE_ID),
|
||||
icon: Sparkles,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const extraHelpItems = React.useMemo<HelpItem[]>(
|
||||
() => [
|
||||
{
|
||||
title: "Демо дашборд",
|
||||
description: "Посмотрите пример рабочего пространства со всеми разделами.",
|
||||
href: buildRoute.dashboard(DEMO_WORKSPACE_ID),
|
||||
icon: Sparkles,
|
||||
},
|
||||
{
|
||||
title: "Открыть обучение",
|
||||
description: "Запустите интерактивный тур по основным разделам.",
|
||||
action: openTraining,
|
||||
icon: MonitorPlay,
|
||||
},
|
||||
],
|
||||
[openTraining]
|
||||
);
|
||||
|
||||
const renderExtraHelpItem = React.useCallback((item: HelpItem) => {
|
||||
const renderHelpSubItem = React.useCallback((item: HelpItem) => {
|
||||
const content = (
|
||||
<>
|
||||
<item.icon className="mt-1.5 size-3 shrink-0 text-muted-foreground" />
|
||||
<p className="text-xs font-light mt-1.5">{item.title}</p>
|
||||
<item.icon className="mt-1.5 size-3 shrink-0 !text-muted-foreground/90" />
|
||||
<p className="text-xs font-light mt-1.5 text-muted-foreground/90 flex-1">{item.title}</p>
|
||||
{item.external && (
|
||||
<ArrowUpRight className="mt-1.5 size-3 shrink-0 !text-muted-foreground/60" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -639,17 +630,17 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
style={expandedLogoDimensions}
|
||||
>
|
||||
<Image
|
||||
src="/logo_full_dark.webp"
|
||||
width={expandedLogoWidth}
|
||||
height={expandedLogoHeight}
|
||||
src="/logo_full_dark.png"
|
||||
width={expandedLogoWidth*2}
|
||||
height={expandedLogoHeight*2}
|
||||
alt="Smartpost"
|
||||
className="shrink-0 dark:hidden"
|
||||
style={expandedLogoDimensions}
|
||||
/>
|
||||
<Image
|
||||
src="/logo_full_white_2.png"
|
||||
width={expandedLogoWidth}
|
||||
height={expandedLogoHeight}
|
||||
src="/logo_full_white.png"
|
||||
width={expandedLogoWidth*2}
|
||||
height={expandedLogoHeight*2}
|
||||
alt="Smartpost"
|
||||
className="hidden shrink-0 dark:block"
|
||||
style={expandedLogoDimensions}
|
||||
@@ -675,33 +666,40 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
<SidebarGroup className="px-0">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{supportLinks.map((link) => (
|
||||
<SidebarMenuItem key={link.title}>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
size="sm"
|
||||
tooltip={isSidebarCollapsed ? link.title : undefined}
|
||||
{/* Наш канал */}
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
size="sm"
|
||||
tooltip={isSidebarCollapsed ? channelLink.title : undefined}
|
||||
>
|
||||
<a
|
||||
href={channelLink.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
{link.external ? (
|
||||
<a
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<link.icon className="size-4" />
|
||||
<span>{link.title}</span>
|
||||
</a>
|
||||
) : (
|
||||
<Link href={link.href} className="flex items-center gap-2">
|
||||
<link.icon className="size-4" />
|
||||
<span>{link.title}</span>
|
||||
</Link>
|
||||
)}
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
<channelLink.icon className="size-4 text-muted-foreground/90" />
|
||||
<span className="text-muted-foreground/90">{channelLink.title}</span>
|
||||
<ArrowUpRight className="ml-auto size-3.5 text-muted-foreground/60" />
|
||||
</a>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
|
||||
{/* Обучение */}
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
size="sm"
|
||||
tooltip={isSidebarCollapsed ? "Обучение" : undefined}
|
||||
onClick={openTraining}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<MonitorPlay className="size-4 text-muted-foreground/90" />
|
||||
<span className="text-muted-foreground/90">Обучение</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
|
||||
{/* Помощь с подменю */}
|
||||
{isSidebarCollapsed ? (
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenu>
|
||||
@@ -712,10 +710,10 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
className="justify-between"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<LifeBuoy className="size-4" />
|
||||
<span>Помощь</span>
|
||||
<LifeBuoy className="size-4 text-muted-foreground/90" />
|
||||
<span className="text-muted-foreground/90">Помощь</span>
|
||||
</div>
|
||||
<ChevronRight className="size-4 opacity-60" />
|
||||
<ChevronRight className="size-4 text-muted-foreground/60" />
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
@@ -723,9 +721,9 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
align="start"
|
||||
className="min-w-[280px] space-y-1"
|
||||
>
|
||||
{extraHelpItems.map((item) => (
|
||||
{helpSubItems.map((item) => (
|
||||
<DropdownMenuItem key={item.title} asChild>
|
||||
{renderExtraHelpItem(item)}
|
||||
{renderHelpSubItem(item)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
@@ -740,18 +738,18 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
className="justify-between"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<LifeBuoy className="size-4" />
|
||||
<span>Помощь</span>
|
||||
<LifeBuoy className="size-4 text-muted-foreground/90" />
|
||||
<span className="text-muted-foreground/90">Помощь</span>
|
||||
</div>
|
||||
<ChevronRight className="size-4 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
||||
<ChevronRight className="size-4 text-muted-foreground/60 transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" />
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{extraHelpItems.map((item) => (
|
||||
{helpSubItems.map((item) => (
|
||||
<SidebarMenuSubItem key={item.title}>
|
||||
<SidebarMenuSubButton asChild className="">
|
||||
{renderExtraHelpItem(item)}
|
||||
{renderHelpSubItem(item)}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user