feat: new layout

This commit is contained in:
dextmorgn
2025-03-30 23:46:42 +02:00
parent 6780c7af11
commit bb8c03e6ea
16 changed files with 340 additions and 185 deletions

View File

@@ -18,7 +18,6 @@ export default function TokensPage() {
])
return (
<DashboardLayout items={[{ name: "Dashboard", href: "/dashboard" }, { name: "Keys and tokens" }]}>
<div className="space-y-12 container mx-auto py-12 px-8">
<div>
<div className="flex justify-between items-start mb-4">
@@ -146,7 +145,6 @@ export default function TokensPage() {
</Tabs>
</div>
</div>
</DashboardLayout>
)
}

View File

@@ -1,10 +1,16 @@
import { AppSidebar } from "@/components/app-sidebar"
import { createClient } from "@/lib/supabase/server";
import {
SidebarInset,
SidebarProvider,
} from "@/components/ui/sidebar"
import { redirect } from "next/navigation";
import { Radar, Settings } from "lucide-react";
import { Button } from "@/components/ui/button";
import { MainNav } from "@/components/dashboard/main-nav";
import { NavUser } from "@/components/nav-user";
import { SubNav } from "@/components/dashboard/sub-nav";
import Feedback from "@/components/dashboard/feedback";
import Link from "next/link";
const DashboardLayout = async ({
children,
@@ -18,11 +24,28 @@ const DashboardLayout = async ({
if (userError || !data?.user) {
redirect('/login')
}
return (
<SidebarProvider>
<AppSidebar user={data?.user} />
<SidebarInset>
<div className="flex flex-1 flex-col gap-4">
<div className="flex flex-col flex-1 min-h-screen flex-col bg-background">
<header className="sticky top-0 z-50 bg-background border-b">
<div className="flex h-14 items-center px-4">
<Link href="/dashboard" className="flex items-center gap-1">
<Radar className="mr-2 h-6 w-6" />
<h2 className="text-lg font-semibold mr-6">flowsint</h2>
</Link>
<MainNav className="mx-6" />
<div className="ml-auto flex items-center space-x-2">
<div className="lg:flex hidden items-center space-x-2">
<Feedback />
<Button size={"sm"} variant={"ghost"}>Changelog</Button>
<Button size={"sm"} variant={"ghost"}>Docs</Button>
</div>
<NavUser user={data?.user} />
</div>
</div>
</header>
{children}
</div>
</SidebarInset>

View File

@@ -17,6 +17,7 @@ import NewProject from "@/components/dashboard/new-project"
import { AvatarList } from "@/components/avatar-list"
import { cn } from "@/lib/utils"
import DashboardLayout from "@/components/dashboard/layout"
import { SubNav } from "@/components/dashboard/sub-nav"
const DashboardPage = () => {
const [searchQuery, setSearchQuery] = useState("")
@@ -38,7 +39,10 @@ const DashboardPage = () => {
)
return (
<DashboardLayout items={[{ name: "Dashboard" }, { name: "Projects" }]}>
<>
<div className="sticky z-40 bg-background w-full hidden md:flex top-[56px] border-b">
<SubNav />
</div>
<div className="w-full space-y-8 container mx-auto py-12 px-8">
<div>
<h1 className="text-3xl font-bold">Welcome back, Eliott</h1>
@@ -160,7 +164,7 @@ const DashboardPage = () => {
</div>
)}
</div>
</DashboardLayout>
</>
)
}

View File

@@ -1,37 +0,0 @@
"use client"
import { useQuery } from "@tanstack/react-query"
import InvestigationGraph from "@/components/investigations/sketch/graph"
import LargeInvestigationGraph from '@/components/investigations/sketch/large-data-graph'
import IndividualModal from "@/components/investigations/individual-modal"
import { notFound } from "next/navigation"
import { useQueryState } from "nuqs"
interface ProfileProps {
projectId: string
individualId: string
}
export default function DashboardClient({ projectId, individualId }: ProfileProps) {
// Use the initial data from the server, but enable background updates
const [view, _] = useQueryState("view", { defaultValue: "flow-graph" })
const graphQuery = useQuery({
queryKey: ["project", individualId, "individuals", individualId],
queryFn: async () => {
const res = await fetch(`/api/projects/${projectId}/individuals/${individualId}`)
if (!res.ok) {
notFound()
}
return res.json()
},
refetchOnWindowFocus: true,
})
return (
<div>
{view === "flow-graph" ?
<InvestigationGraph graphQuery={graphQuery} />
:
<LargeInvestigationGraph graphQuery={graphQuery} />
}
<IndividualModal />
</div>
)
}

View File

@@ -5,6 +5,7 @@ import LargeInvestigationGraph from '@/components/investigations/sketch/large-da
import IndividualModal from "@/components/investigations/individual-modal"
import { notFound } from "next/navigation"
import { useQueryState } from "nuqs"
import { InvestigationtNavigation } from "@/components/investigations/investigation-navigation"
interface DashboardClientProps {
projectId: string
investigationId: string
@@ -24,14 +25,17 @@ export default function DashboardClient({ projectId, investigationId }: Dashboar
refetchOnWindowFocus: true,
})
return (
<div>
<>
<div className="sticky z-40 bg-background top-[56px] border-b">
<InvestigationtNavigation project_id={projectId} investigation_id={investigationId} />
</div>
{view === "flow-graph" ?
<InvestigationGraph graphQuery={graphQuery} />
:
<LargeInvestigationGraph graphQuery={graphQuery} />
}
<IndividualModal />
</div>
</>
)
}

View File

@@ -11,19 +11,11 @@ import Loader from "@/components/loader"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { format, formatDistanceToNow } from "date-fns"
import Link from "next/link"
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
import { Investigation } from "@/types/investigation"
import NewCase from "@/components/dashboard/new-sketch"
import { DocumentList } from "@/components/projects/documents-list"
import { cn } from "@/lib/utils"
import DashboardLayout from "@/components/dashboard/layout"
import { ProjectNavigation } from "@/components/investigations/project-navigation"
const DashboardPage = () => {
const { project_id } = useParams()
@@ -64,7 +56,10 @@ const DashboardPage = () => {
const isRefetching = isRefetchingDocs || isRefetchingSketches
return (
<DashboardLayout items={[{ name: "Projects", href: "/dashboard" }, { name: project?.name || "..." }]}>
<>
<div className="sticky z-40 bg-background top-[56px] border-b">
<ProjectNavigation project_id={project_id as string} />
</div>
<div className="w-full space-y-8 container mx-auto py-12 px-8">
<div className="flex items-center gap-2 justify-between mb-6">
<div className="relative w-full max-w-md">
@@ -180,7 +175,7 @@ const DashboardPage = () => {
</div>
)}
</div>
</DashboardLayout>
</>
)
}

View File

@@ -39,22 +39,20 @@ interface SettingsLayoutProps {
export default function SettingsLayout({ children }: SettingsLayoutProps) {
return (
<DashboardLayout items={[{ name: "Dashboard", href: "/dashboard" }, { name: "Settings" }]}>
<div className="space-y-12 container mx-auto py-12 px-8">
<div className="space-y-0.5">
<h2 className="text-2xl font-bold tracking-tight">Settings</h2>
<p className="text-muted-foreground">
Manage your account settings and set e-mail preferences.
</p>
</div>
<Separator className="my-6" />
<div className="flex flex-col space-y-8 md:flex-row space-x-12 gap-6">
<aside className="lg:w-1/5">
<SidebarNav items={sidebarNavItems} />
</aside>
<div className="flex-1 md:max-w-2xl">{children}</div>
</div>
<div className="space-y-12 container mx-auto py-12 px-8">
<div className="space-y-0.5">
<h2 className="text-2xl font-bold tracking-tight">Settings</h2>
<p className="text-muted-foreground">
Manage your account settings and set e-mail preferences.
</p>
</div>
</DashboardLayout>
<Separator className="my-6" />
<div className="flex flex-col space-y-8 md:flex-row space-x-12 gap-6">
<aside className="lg:w-1/5">
<SidebarNav items={sidebarNavItems} />
</aside>
<div className="flex-1 md:max-w-2xl">{children}</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,47 @@
"use client"
import type React from "react"
import Link from "next/link"
import { cn } from "@/lib/utils"
import ProjectSelector from "../investigations/project-selector"
import CaseSelector from "../investigations/case-selector"
import { useParams } from "next/navigation"
export function MainNav({ className, ...props }: React.HTMLAttributes<HTMLElement>) {
const { investigation_id, project_id } = useParams()
if (project_id) return (
<div className='flex gap-1 items-center p-2'>
<ProjectSelector />{investigation_id && <><span className='opacity-60'>/</span><CaseSelector /></>}
</div >
)
return (
<nav className={cn("md:flex hidden w-full items-center space-x-4 lg:space-x-6", className)} {...props}>
<Link
href="/"
className="text-sm font-medium transition-colors hover:text-primary bg-muted/50 px-3 py-1.5 rounded-md"
>
Dashboard
</Link>
<Link
href="/sources"
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary px-3 py-1.5 rounded-md"
>
Sources
</Link>
<Link
href="/analyses"
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary px-3 py-1.5 rounded-md"
>
Analyses
</Link>
<Link
href="/templates"
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary px-3 py-1.5 rounded-md"
>
Templates
</Link>
</nav>
)
}

View File

@@ -0,0 +1,73 @@
"use client"
import { cn } from "@/lib/utils"
import { Eye, Users, Camera, Database, Settings } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { useState } from "react"
export function SubNav() {
const pathname = usePathname()
const sections = [
{
id: "overview",
name: "Overview",
href: "/dashboard",
icon: Eye,
count: 18,
},
{
id: "investigations",
name: "Investigations",
href: "/dashboard/investigations",
icon: Users,
count: 24,
},
{
id: "surveillance",
name: "Surveillance",
href: "/dashboard/surveillance",
icon: Camera,
count: 6,
},
{
id: "intelligence",
name: "Intelligence",
href: "/dashboard/intelligence",
icon: Database,
count: 16,
},
{
id: "configurations",
name: "Configurations",
href: "/dashboard/settings",
icon: Settings,
count: null,
},
]
return (
<div className="flex overflow-auto">
{sections.map((section) => (
<Link
key={section.id}
href={section?.href || ""}
className={cn(
"flex items-center text-xs gap-2 px-4 py-2 transition-colors",
section?.href == pathname
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
)}
>
<section.icon className="h-4 w-4" />
<span>{section.name}</span>
{section.count !== null && (
<span className="ml-1 rounded-full bg-primary/10 px-2 py-0.5 text-xs">{section.count}</span>
)}
</Link>
))}
</div>
)
}

View File

@@ -1,3 +1,4 @@
"use client"
import { useInvestigations } from "@/lib/hooks/investigation/investigation";
import { useInvestigationStore } from '@/store/investigation-store';
import { useParams, useRouter } from "next/navigation";

View File

@@ -89,9 +89,9 @@ const IndividualModal = () => {
return (
<Dialog open={Boolean(individualId)} onOpenChange={handleCloseModal}>
<DialogContent className="sm:max-w-[90vw] max-h-[90vh] p-0 bg-black text-white border-zinc-800 overflow-hidden">
<DialogContent className="sm:max-w-[90vw] max-h-[90vh] p-0 bg-background overflow-y-auto">
<div className="h-full flex flex-col">
<div className="flex justify-between items-center p-4 border-b border-zinc-800">
<div className="flex justify-between sticky top-0 items-center p-4 border-b">
<DialogTitle className="text-xl font-bold">{individual?.full_name || "User Profile"}</DialogTitle>
<div className="flex items-center gap-2 mr-12">
<Button
@@ -119,10 +119,10 @@ const IndividualModal = () => {
<div className="flex flex-col md:flex-row gap-6">
{/* Left column - Profile image and basic info */}
<div className="flex flex-col gap-4 md:w-1/3">
<div className="flex flex-col items-center gap-4 bg-zinc-900 rounded-xl p-6">
<Avatar className="h-32 w-32 border-2 border-zinc-700">
<div className="flex flex-col items-center gap-4 rounded-xl p-6">
<Avatar className="h-32 w-32 border-2">
<AvatarImage src={image || undefined} alt={individual?.full_name} />
<AvatarFallback className="bg-zinc-800 text-zinc-300 text-2xl">
<AvatarFallback className="bg-zinc-800 text-2xl">
{individual?.full_name?.[0] || "?"}
</AvatarFallback>
</Avatar>
@@ -134,35 +134,35 @@ const IndividualModal = () => {
<div className="w-full space-y-4 mt-2">
{individual?.email && (
<div className="flex items-center gap-3 text-sm">
<Mail className="h-4 w-4 text-zinc-500" />
<span className="text-zinc-300">{individual.email}</span>
<Mail className="h-4 w-4" />
<span className="">{individual.email}</span>
</div>
)}
{phones[0] && (
<div className="flex items-center gap-3 text-sm">
<Phone className="h-4 w-4 text-zinc-500" />
<span className="text-zinc-300">{phones[0]}</span>
<Phone className="h-4 w-4" />
<span className="">{phones[0]}</span>
</div>
)}
{individual?.location && (
<div className="flex items-center gap-3 text-sm">
<MapPin className="h-4 w-4 text-zinc-500" />
<span className="text-zinc-300">{individual.location}</span>
<MapPin className="h-4 w-4" />
<span className="">{individual.location}</span>
</div>
)}
{individual?.company && (
<div className="flex items-center gap-3 text-sm">
<Building2 className="h-4 w-4 text-zinc-500" />
<span className="text-zinc-300">{individual.company}</span>
<Building2 className="h-4 w-4" />
<span className="">{individual.company}</span>
</div>
)}
</div>
</div>
<div className="bg-zinc-900 rounded-xl p-6">
<div className="bg-background rounded-xl p-6">
<h3 className="text-lg font-semibold mb-4">Profile</h3>
<div className="space-y-3">
{individual?.birth_date && (
@@ -203,7 +203,7 @@ const IndividualModal = () => {
</div>
{/* Score card */}
<div className="bg-zinc-900 rounded-xl p-6">
<div className="bg-background rounded-xl p-6">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold">Overall score</h3>
<div className="relative h-16 w-16">
@@ -265,7 +265,7 @@ const IndividualModal = () => {
{/* Right column - Tabs content */}
<div className="flex-1">
<Tabs defaultValue="overview" className="w-full">
<TabsList className="w-full justify-start bg-zinc-900 p-1 rounded-lg mb-4">
<TabsList className="w-full justify-start p-1 rounded-lg mb-4">
<TabsTrigger
value="overview"
className="data-[state=active]:bg-zinc-800 data-[state=active]:text-white"
@@ -319,7 +319,7 @@ const IndividualModal = () => {
</TabsTrigger>
</TabsList>
<div className="bg-zinc-900 rounded-xl p-6">
<div className="bg-background rounded-xl p-6">
<TabsContent value="overview">
{editMode ? (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
@@ -335,7 +335,7 @@ const IndividualModal = () => {
placeholder={key}
name={key}
disabled={key === "id" || key === "investigation_id" || !editMode}
className="bg-zinc-800 border-zinc-700 text-white"
className="bg-zinc-800 text-white"
/>
</div>
))}
@@ -405,12 +405,12 @@ const IndividualModal = () => {
)}
{accounts.map((account: any, index) => (
<Card key={index} className="bg-zinc-800 border-zinc-700 p-4">
<Card key={index} className="bg-zinc-800 p-4">
<CardContent className="flex items-center gap-3 p-0">
<Avatar className="h-10 w-10 bg-zinc-700">
{/* @ts-ignore */}
<AvatarImage src={platformsIcons[account?.platform]?.icon} />
<AvatarFallback className="bg-zinc-700 text-zinc-300">
<AvatarFallback className="bg-zinc-700 ">
{account?.platform?.[0] || "?"}
</AvatarFallback>
</Avatar>
@@ -446,7 +446,7 @@ const IndividualModal = () => {
<Button
onClick={() => handleAddField(setAccounts)}
variant="outline"
className="border-dashed border-zinc-700 hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
className="border-dashed hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
>
<Plus className="mr-2 h-4 w-4" /> Add account
</Button>
@@ -469,7 +469,7 @@ const IndividualModal = () => {
className={
email.breaches.length > 0
? "bg-red-950/50 border-red-900 text-red-200"
: "bg-zinc-800 border-zinc-700"
: "bg-zinc-800"
}
>
<AlertDescription className="flex items-center gap-2">
@@ -496,7 +496,7 @@ const IndividualModal = () => {
{phones.map((phone, index) => (
<div key={index} className="flex items-center gap-2">
<div className="bg-zinc-800 border border-zinc-700 rounded-md p-3 flex items-center gap-3 flex-1">
<div className="bg-zinc-800 border rounded-md p-3 flex items-center gap-3 flex-1">
<Phone className="h-4 w-4 text-zinc-400" />
{editMode ? (
<Input
@@ -528,7 +528,7 @@ const IndividualModal = () => {
<Button
onClick={() => handleAddField(setPhones)}
variant="outline"
className="border-dashed border-zinc-700 hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
className="border-dashed hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
>
<Plus className="mr-2 h-4 w-4" /> Add Phone
</Button>
@@ -546,7 +546,7 @@ const IndividualModal = () => {
{ips.map((ip, index) => (
<div key={index} className="flex items-center gap-2">
<div className="bg-zinc-800 border border-zinc-700 rounded-md p-3 flex items-center gap-3 flex-1">
<div className="bg-zinc-800 border rounded-md p-3 flex items-center gap-3 flex-1">
<svg
className="h-4 w-4 text-zinc-400"
viewBox="0 0 24 24"
@@ -605,7 +605,7 @@ const IndividualModal = () => {
<Button
onClick={() => handleAddField(setIps)}
variant="outline"
className="border-dashed border-zinc-700 hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
className="border-dashed hover:border-zinc-500 bg-transparent text-zinc-400 hover:text-white hover:bg-zinc-800"
>
<Plus className="mr-2 h-4 w-4" /> Add IP address
</Button>
@@ -624,13 +624,13 @@ const IndividualModal = () => {
{relations.map((relation) => (
<Card
key={relation.id}
className="bg-zinc-800 border-zinc-700 p-4 hover:bg-zinc-750 transition-colors cursor-pointer"
className="bg-zinc-800 p-4 hover:bg-zinc-750 transition-colors cursor-pointer"
onClick={() => setIndividualId(relation.id)}
>
<CardContent className="flex items-center gap-3 p-0">
<Avatar className="h-10 w-10 border border-zinc-700">
<Avatar className="h-10 w-10 border">
<AvatarImage src={relation?.image_url} alt={relation.full_name} />
<AvatarFallback className="bg-zinc-700 text-zinc-300">
<AvatarFallback className="bg-zinc-700 ">
{relation.full_name?.[0] || "?"}
</AvatarFallback>
</Avatar>
@@ -652,7 +652,7 @@ const IndividualModal = () => {
<Button
variant="outline"
onClick={() => setEditMode(false)}
className="bg-transparent border-zinc-700 text-zinc-300 hover:bg-zinc-800 hover:text-white"
className="bg-transparent hover:bg-zinc-800 hover:text-white"
>
Cancel
</Button>

View File

@@ -0,0 +1,62 @@
"use client"
import { cn } from "@/lib/utils"
import { Users, TimerIcon, MapIcon, WaypointsIcon } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
export function InvestigationtNavigation({ project_id, investigation_id }: { project_id: string, investigation_id: string }) {
const pathname = usePathname()
const sections = [
{
id: "sketch",
name: "Sketch",
href: `/dashboard/projects/${project_id}/investigations/${investigation_id}`,
icon: WaypointsIcon
},
{
id: "individuals",
name: "Individuals",
href: `/dashboard/projects/${project_id}/investigations/${investigation_id}/individuals`,
icon: Users,
count: 24,
},
{
id: "timeline",
name: "Timeline",
href: `/dashboard/projects/${project_id}/investigations/${investigation_id}/timeline`,
icon: TimerIcon,
},
{
id: "map",
name: "Map",
href: `/dashboard/projects/${project_id}/investigations/${investigation_id}/map`,
icon: MapIcon,
},
]
return (
<div className="flex overflow-auto">
{sections.map((section) => (
<Link
key={section.id}
href={section?.href || ""}
className={cn(
"flex items-center text-xs gap-2 px-4 py-2 transition-colors",
section?.href == pathname
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
)}
>
<section.icon className="h-4 w-4" />
<span>{section.name}</span>
{section.count && (
<span className="ml-1 rounded-full bg-primary/10 px-2 py-0.5 text-xs">{section.count}</span>
)}
</Link>
))}
</div>
)
}

View File

@@ -1,75 +1,16 @@
"use client"
import React from 'react'
import MoreMenu from './more-menu';
import CaseSelector from './case-selector';
import NewCase from '@/components/dashboard/new-sketch';
import SearchModal from '@/components/dashboard/search-palette';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { PanelRightIcon, PlusIcon, RotateCwIcon } from 'lucide-react';
import Logo from '@/components/logo';
import { useInvestigationStore } from '@/store/investigation-store';
import { Button } from '../ui/button';
import { ScrollArea } from '../ui/scroll-area';
import Assistant from '../assistant';
import { AppSidebar } from '../app-sidebar';
import { SidebarProvider } from '../ui/sidebar';
import { ScanDrawer } from './scan-drawer';
import { ScanButton } from './scans-drawer/scan-button';
import ProjectSelector from './project-selector';
const InvestigationLayout = ({
children,
left,
investigation_id,
user
}: {
children: React.ReactNode;
left: React.ReactNode;
investigation_id: string
user: any
}) => {
const { panelOpen, setPanelOpen } = useInvestigationStore()
return (
<>
{/* <PanelGroup autoSaveId="conditional" className='h-screen w-screen flex' direction="horizontal"> */}
{/* {panelOpen && <Panel id="left" order={1} className='h-screen' defaultSize={20} minSize={10}>
<div className='flex flex-col w-full h-full rounded-none shadow-none border-r'>
<div className='w-full rounded-none shadow-none h-12 border-b flex items-center gap-1 flex-row justify-end p-2'>
<div className='flex gap-1'>
<SearchModal investigation_id={investigation_id} />
<NewCase>
<Button variant="outline" size="icon">
<PlusIcon className="h-5" />
</Button>
</NewCase>
</div>
</div>
<ScrollArea type="auto" className='h-full grow overflow-y-auto'>
<div className="flex flex-col">
{left}
</div>
</ScrollArea>
</div>
</Panel>}
<PanelResizeHandle /> */}
{/* <Panel id="right" order={2} defaultSize={90} minSize={50} className='grow flex flex-col'> */}
<div>
<div className='w-full bg-sidebar rounded-none shadow-none h-12 justify-between border-b flex flex-row items-center'>
<div className='grow flex items-center justify-between p-2'>
<div className='flex gap-1 items-center p-2'>
<ProjectSelector /><span className='opacity-60'>/</span><CaseSelector />
</div>
<MoreMenu />
</div>
<div className='border-l h-full flex items-center'>
<ScanButton />
</div>
</div>
{children}
</div>
{/* </Panel>
</PanelGroup >
*/}
{children}
<ScanDrawer />
</>
)

View File

@@ -0,0 +1,65 @@
"use client"
import { cn } from "@/lib/utils"
import { Eye, Users, Camera, Settings } from "lucide-react"
import Link from "next/link"
import { usePathname } from "next/navigation"
export function ProjectNavigation({ project_id }: { project_id: string }) {
const pathname = usePathname()
const sections = [
{
id: "overview",
name: "Overview",
href: `/dashboard/projects/${project_id}`,
icon: Eye,
count: 18,
},
{
id: "sketches",
name: "Sketches",
href: `/dashboard/projects/${project_id}?filter=sketch`,
icon: Users,
count: 24,
},
{
id: "documents",
name: "Documents",
href: `/dashboard/projects/${project_id}?filter=document`,
icon: Camera,
count: 6,
},
{
id: "configurations",
name: "Configurations",
href: `/dashboard/projects/${project_id}/settings`,
icon: Settings,
count: null,
},
]
return (
<div className="flex overflow-auto">
{sections.map((section) => (
<Link
key={section.id}
href={section?.href || ""}
className={cn(
"flex items-center text-xs gap-2 px-4 py-2 transition-colors",
section?.href == pathname
? "bg-accent text-accent-foreground"
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
)}
>
<section.icon className="h-4 w-4" />
<span>{section.name}</span>
{section.count !== null && (
<span className="ml-1 rounded-full bg-primary/10 px-2 py-0.5 text-xs">{section.count}</span>
)}
</Link>
))}
</div>
)
}

View File

@@ -170,19 +170,6 @@ const FlowControls = memo(
<TooltipContent>Zoom out</TooltipContent>
</Tooltip>
</Panel>
<Panel position="top-center" className="text-center">
<Tabs defaultValue="sketch">
<TabsList>
<TabsTrigger value="sketch">Sketch</TabsTrigger>
<TabsTrigger value="map" disabled>Map</TabsTrigger>
<TabsTrigger value="timeline" disabled>Timeline</TabsTrigger>
</TabsList>
</Tabs>
</Panel>
{/* {currentNode && (
<Panel position="top-right">
<ProfilePanel type={currentNode.type} data={currentNode.data} />
</Panel>)} */}
</>
)
},
@@ -292,7 +279,7 @@ const LayoutFlow = ({ refetch, theme }: LayoutFlowProps) => {
)
return (
<div className="h-[calc(100vh_-_48px)] relative">
<div className="w-full grow relative">
<TooltipProvider>
<Dialog>
<ContextMenu>
@@ -379,7 +366,7 @@ function Graph({ graphQuery }: { graphQuery: any }) {
if (!mounted || isLoading) {
return (
<div className="h-[calc(100vh_-_48px)] w-full flex items-center justify-center">
<div className="grow w-full flex items-center justify-center">
<Loader /> Loading...
</div>
)

View File

@@ -47,17 +47,11 @@ export function NavUser({
<DropdownMenuTrigger asChild>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
>
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="rounded-lg uppercase">{user.email[0]}</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">{user.name}</span>
<span className="truncate text-xs">{user.email}</span>
</div>
<ChevronsUpDown className="ml-auto size-4" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
@@ -70,7 +64,7 @@ export function NavUser({
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage src={user.avatar} alt={user.name} />
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
<AvatarFallback className="rounded-lg">{user.email[0]}</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">{user.name}</span>