mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-18 13:34:06 +01:00
Merge branch 'front-end' into back-end
This commit is contained in:
commit
38e09f80b6
@ -26,8 +26,12 @@ const nextConfig = {
|
|||||||
hostname: "avatars.githubusercontent.com",
|
hostname: "avatars.githubusercontent.com",
|
||||||
pathname: "/**",
|
pathname: "/**",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "assets.republic.com",
|
||||||
|
pathname: "/**",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@ -98,7 +98,7 @@ export default async function ProjectDealPage({ params }: { params: { id: number
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="sub-content" className="flex flex-row mt-5">
|
<div id="sub-content" className="grid grid-cols-1 md:grid-cols-2 mt-5 space-y-5 md:space-y-0">
|
||||||
{/* image carousel */}
|
{/* image carousel */}
|
||||||
<div id="image-carousel" className="w-full">
|
<div id="image-carousel" className="w-full">
|
||||||
<Gallery images={carouselData} />
|
<Gallery images={carouselData} />
|
||||||
@ -152,62 +152,28 @@ export default async function ProjectDealPage({ params }: { params: { id: number
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between w-full">
|
<div className="flex justify-between gap-4 w-full">
|
||||||
<Button className="w-[48%] h-12 dark:text-white" variant={"outline"}>
|
<Button
|
||||||
<Link href={`/dataroom/${params.id}/files`}>Access Dataroom</Link>
|
className="flex justify-center items-center w-[48%] h-12 text-xs md:text-sm text-center dark:text-white"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<Link href={`/dataroom/${params.id}/files`} className="block text-center break-words">
|
||||||
|
<span className="block lg:inline">Access</span>
|
||||||
|
<span className="block lg:inline"> Dataroom</span>
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="w-[48%] h-12 dark:text-white" variant={"outline"}>
|
<Button
|
||||||
<Link href={`/dataroom/overview`}>Request Dataroom Access</Link>
|
className="flex justify-center items-center w-[48%] h-12 text-xs md:text-sm text-center dark:text-white"
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
|
<Link href={`/dataroom/overview`} className="block text-center break-words">
|
||||||
|
<span className="block lg:inline">Request</span>
|
||||||
|
<span className="block lg:inline"> Dataroom Access</span>
|
||||||
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* <div id="stats" className="flex flex-col w-full mt-4 pl-12">
|
|
||||||
<div className="pl-5">
|
|
||||||
<span>
|
|
||||||
<h1 className="font-semibold text-xl md:text-4xl mt-8">${totalDealAmount}</h1>
|
|
||||||
<p className="text-sm md:text-lg">
|
|
||||||
{toPercentage(totalDealAmount, projectData?.target_investment)}% raised of $
|
|
||||||
{projectData?.target_investment} max goal
|
|
||||||
</p>
|
|
||||||
<Progress
|
|
||||||
value={toPercentage(totalDealAmount, projectData?.target_investment)}
|
|
||||||
className="w-[60%] h-3 mt-3"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<h1 className="font-semibold text-4xl md:mt-8">
|
|
||||||
<p className="text-xl md:text-4xl">{dealList.length}</p>
|
|
||||||
</h1>
|
|
||||||
<p className="text-sm md:text-lg">Investors</p>
|
|
||||||
</span>
|
|
||||||
<Separator decorative className="mt-3 w-3/4 ml-5" />
|
|
||||||
<span>
|
|
||||||
<h1 className="font-semibold text-xl md:text-4xl mt-8 ml-5"></h1>
|
|
||||||
{projectData?.investment_deadline ? (
|
|
||||||
<>
|
|
||||||
<p className="text-xl md:text-4xl">{Math.floor(hourLeft)} hours</p>
|
|
||||||
<p>Left to invest</p>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p className="text-xl md:text-4xl">No deadline</p>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<Button className="mt-5 w-3/4 h-12 dark:text-white">
|
|
||||||
<Link href={`/invest/${params.id}`}>Invest in {projectData?.project_name}</Link>
|
|
||||||
</Button>
|
|
||||||
<div className="flex flex-col space-y-2 py-4 mt-5 w-3/4 h-12 border-2 border-border rounded-md">
|
|
||||||
<p className="text-md font-bold">Dataroom</p>
|
|
||||||
<Button className=" dark:text-white">
|
|
||||||
<Link href={`/invest/${params.id}`}>Access Dataroom</Link>
|
|
||||||
</Button>
|
|
||||||
<Button className=" dark:text-white">
|
|
||||||
<Link href={`/invest/${params.id}`}>Manage Dataroom</Link>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
{/* menu */}
|
{/* menu */}
|
||||||
<div id="deck">
|
<div id="deck">
|
||||||
@ -215,7 +181,6 @@ export default async function ProjectDealPage({ params }: { params: { id: number
|
|||||||
<Tabs.Root defaultValue="pitch" className="w-full">
|
<Tabs.Root defaultValue="pitch" className="w-full">
|
||||||
<Tabs.List className="list-none flex gap-10 text-lg md:text-xl">
|
<Tabs.List className="list-none flex gap-10 text-lg md:text-xl">
|
||||||
<Tabs.Trigger value="pitch">Pitch</Tabs.Trigger>
|
<Tabs.Trigger value="pitch">Pitch</Tabs.Trigger>
|
||||||
{/* <Tabs.Trigger value="general">General Data</Tabs.Trigger> */}
|
|
||||||
<Tabs.Trigger value="update">Updates</Tabs.Trigger>
|
<Tabs.Trigger value="update">Updates</Tabs.Trigger>
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
<Separator className="mb-4 mt-2 w-full border-1" />
|
<Separator className="mb-4 mt-2 w-full border-1" />
|
||||||
@ -235,17 +200,6 @@ export default async function ProjectDealPage({ params }: { params: { id: number
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
{/* <Tabs.Content value="general">
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>general</CardTitle>
|
|
||||||
<CardDescription>general Description</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<p>general Content</p>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</Tabs.Content> */}
|
|
||||||
<Tabs.Content value="update">
|
<Tabs.Content value="update">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
31
src/app/(legal)/about/infoCard.tsx
Normal file
31
src/app/(legal)/about/infoCard.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
type CardProps = {
|
||||||
|
imageSrc: string;
|
||||||
|
imageAlt: string;
|
||||||
|
heading: string;
|
||||||
|
content: string[];
|
||||||
|
link: string;
|
||||||
|
buttonText: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const InfoCard = ({ imageSrc, imageAlt, heading, content, link, buttonText }: CardProps) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center">
|
||||||
|
<Image alt={imageAlt} width={460} height={460} className="w-36" src={imageSrc} />
|
||||||
|
<h1 className="text-2xl font-bold mt-3">{heading}</h1>
|
||||||
|
{content.map((text, index) => (
|
||||||
|
<p key={index} className={index === 0 ? "mt-3" : ""}>
|
||||||
|
{text}
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
<Link href={link}>
|
||||||
|
<Button className="p-6 font-semibold text-base mt-5">{buttonText}</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InfoCard;
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import Image from "next/image";
|
"use client";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import InfoCard from "./infoCard";
|
||||||
|
|
||||||
export default function About() {
|
export default function About() {
|
||||||
// Static data for the cards
|
// Static data for the cards
|
||||||
@ -38,11 +39,69 @@ export default function About() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const imageData = {
|
||||||
|
img1: "https://assets.republic.com/assets/static_pages/about/growth_opportunities/individual_investors-0e85dfd02359a24ac4b232be008c7168fc57d3437a2f526f5d5889b874b20221.png",
|
||||||
|
img2: "https://assets.republic.com/assets/static_pages/about/growth_opportunities/accredited_investors-42d6aa046861adb7f0648f26ca3f798b07f3b13bf7024f7dc17c17acb78fdf2c.png",
|
||||||
|
img3: "https://assets.republic.com/assets/static_pages/about/growth_opportunities/entrepreneurs-a0ff450c2f3ba0cea82e2c55cd9265ad5612455c79ec831adaa2c94d09a0e617.png",
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container max-w-screen-xl p-10">
|
<div className="container max-w-screen-xl p-10">
|
||||||
<h1 className="mt-3 font-bold text-lg md:text-3xl">About us</h1>
|
<div className="flex flex-col items-center justify-center">
|
||||||
<Separator className="my-3" />
|
<h1 className="mt-3 font-bold text-lg md:text-5xl font-black">Growth opportunities for all sides </h1>
|
||||||
<div className="border border-border rounded-md">
|
<h1 className="mt-3 font-bold text-lg md:text-5xl font-black">of the investment market</h1>
|
||||||
|
<h1 className="text-gray-500 text-2xl mt-1">
|
||||||
|
B2DVentures is where both accredited and non-accredited investors meet
|
||||||
|
</h1>
|
||||||
|
<h1 className="text-gray-500 text-2xl">entrepreneurs and access high-growth potential deals across a range</h1>
|
||||||
|
<h1 className="text-gray-500 text-2xl">of private markets.</h1>
|
||||||
|
</div>
|
||||||
|
<div className="mt-10">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-[1fr,auto,1fr] gap-3">
|
||||||
|
<InfoCard
|
||||||
|
imageSrc={imageData.img1}
|
||||||
|
imageAlt="Image1"
|
||||||
|
heading="Individual investors"
|
||||||
|
content={[
|
||||||
|
"B2DVentures's success has been built off our hundreds",
|
||||||
|
"of sourced private deals, all available for",
|
||||||
|
"investment from you with as little as $10 or as ",
|
||||||
|
"much as $124,000.",
|
||||||
|
]}
|
||||||
|
link="/deals"
|
||||||
|
buttonText="Explore opportunities"
|
||||||
|
/>
|
||||||
|
<Separator orientation="vertical" />
|
||||||
|
<InfoCard
|
||||||
|
imageSrc={imageData.img2}
|
||||||
|
imageAlt="Image2"
|
||||||
|
heading="Accredited investors"
|
||||||
|
content={[
|
||||||
|
"The benefits of the Republic platform, optimized for",
|
||||||
|
"accredited investors. Access a curated investor",
|
||||||
|
"portal for unique private investment opportunities. ",
|
||||||
|
]}
|
||||||
|
link="/dataroom/overview"
|
||||||
|
buttonText="Learn more"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Separator className="mt-5 mb-5" />
|
||||||
|
<InfoCard
|
||||||
|
imageSrc={imageData.img3}
|
||||||
|
imageAlt="Image3"
|
||||||
|
heading="Entrepreneurs"
|
||||||
|
content={[
|
||||||
|
"Seek funding from a wider base of diverse",
|
||||||
|
"investors while simultaneously growing a loyal",
|
||||||
|
"base and leveraging Republic’s private investment",
|
||||||
|
"network.",
|
||||||
|
]}
|
||||||
|
link="/project/apply"
|
||||||
|
buttonText="Raise money"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <div className="border border-border rounded-md">
|
||||||
<p className="p-5">
|
<p className="p-5">
|
||||||
Welcome to B2D Ventures! We're a dynamic platform committed to bridging the gap between visionary
|
Welcome to B2D Ventures! We're a dynamic platform committed to bridging the gap between visionary
|
||||||
entrepreneurs and passionate investors. Our mission is to empower innovation by connecting groundbreaking
|
entrepreneurs and passionate investors. Our mission is to empower innovation by connecting groundbreaking
|
||||||
@ -56,15 +115,15 @@ export default function About() {
|
|||||||
lasting impact.
|
lasting impact.
|
||||||
</p>
|
</p>
|
||||||
<p className="p-5">Let's build the future, together.</p>
|
<p className="p-5">Let's build the future, together.</p>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div className="mt-10 text-center">
|
{/* <div className="mt-10 text-center">
|
||||||
<h2 className="font-bold text-lg md:text-3xl">Our Team</h2>
|
<h2 className="font-bold text-lg md:text-3xl">Our Team</h2>
|
||||||
<Separator className="my-3" />
|
<Separator className="my-3" />
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
{/* Card Section */}
|
{/* Card Section */}
|
||||||
<div className="mt-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
{/* <div className="mt-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
{cardData.map((card, index) => (
|
{cardData.map((card, index) => (
|
||||||
<div key={index} className="bg-white rounded-lg shadow-lg overflow-hidden">
|
<div key={index} className="bg-white rounded-lg shadow-lg overflow-hidden">
|
||||||
<Image src={card.imageSrc} width={460} height={460} alt={card.name} className="w-full h-48 object-cover" />
|
<Image src={card.imageSrc} width={460} height={460} alt={card.name} className="w-full h-48 object-cover" />
|
||||||
@ -74,7 +133,7 @@ export default function About() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export default function ProjectCardCalendarManageSection({ projectData }: Projec
|
|||||||
const [currentProjectId, setCurrentProjectId] = useState<number | undefined>(undefined);
|
const [currentProjectId, setCurrentProjectId] = useState<number | undefined>(undefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="content" className="grid grid-cols-2 space-x-2">
|
<div id="content" className="grid grid-cols-1 md:grid-cols-2 space-x-2">
|
||||||
{projectData != null ? (
|
{projectData != null ? (
|
||||||
projectData.map((project) => (
|
projectData.map((project) => (
|
||||||
<Card key={project.id} className="mb-3">
|
<Card key={project.id} className="mb-3">
|
||||||
|
|||||||
@ -208,7 +208,7 @@ export function DataTable({ data }: { data: ModalProps[] }) {
|
|||||||
placeholder="Filter names..."
|
placeholder="Filter names..."
|
||||||
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
|
value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
|
||||||
onChange={(event) => table.getColumn("name")?.setFilterValue(event.target.value)}
|
onChange={(event) => table.getColumn("name")?.setFilterValue(event.target.value)}
|
||||||
className="max-w-sm"
|
className="md:max-w-sm max-w-xs"
|
||||||
/>
|
/>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
|
|||||||
28
src/components/listItem.tsx
Normal file
28
src/components/listItem.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { NavigationMenuLink } from "@/components/ui/navigation-menu";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import React from "react";
|
||||||
|
const ListItem = React.forwardRef<React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(
|
||||||
|
({ className, title, children, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<NavigationMenuLink asChild>
|
||||||
|
<a
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<div className="text-sm font-medium leading-none">{title}</div>
|
||||||
|
<hr />
|
||||||
|
<p className="line-clamp-2 text-sm leading-snug text-muted-foreground">{children}</p>
|
||||||
|
</a>
|
||||||
|
</NavigationMenuLink>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ListItem.displayName = "ListItem";
|
||||||
|
|
||||||
|
export default ListItem;
|
||||||
@ -1,27 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { Menu, X } from "lucide-react";
|
|
||||||
import { Button } from "./ui/button";
|
|
||||||
import { motion } from "framer-motion";
|
|
||||||
|
|
||||||
export function MobileMenu() {
|
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Button onClick={() => setIsVisible((prev) => !prev)}>
|
|
||||||
<Menu />
|
|
||||||
</Button>
|
|
||||||
{isVisible && (
|
|
||||||
<motion.div
|
|
||||||
initial={{ x: "-100%" }}
|
|
||||||
animate={{ x: 0 }}
|
|
||||||
exit={{ x: "-100%" }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
className="fixed top-0 left-0 w-full bg-gray-800 text-white"
|
|
||||||
>
|
|
||||||
<X className="cursor-pointer" onClick={() => setIsVisible(false)} />
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
23
src/components/navigationBar/menu.ts
Normal file
23
src/components/navigationBar/menu.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export const businessComponents = [
|
||||||
|
{
|
||||||
|
title: "Business",
|
||||||
|
href: "/business/apply",
|
||||||
|
description: "Apply to raise on on B2DVentures",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const projectComponents = [
|
||||||
|
{
|
||||||
|
title: "Projects",
|
||||||
|
href: "/project/apply",
|
||||||
|
description: "Start your new project on B2DVentures",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const dataroomComponents = [
|
||||||
|
{
|
||||||
|
title: "Overview",
|
||||||
|
href: "/dataroom/overview",
|
||||||
|
description: "View all dataroom available to you",
|
||||||
|
},
|
||||||
|
];
|
||||||
103
src/components/navigationBar/mobileMenu.tsx
Normal file
103
src/components/navigationBar/mobileMenu.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
"use client";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Menu, X } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
import {
|
||||||
|
NavigationMenu,
|
||||||
|
NavigationMenuContent,
|
||||||
|
NavigationMenuItem,
|
||||||
|
NavigationMenuLink,
|
||||||
|
NavigationMenuList,
|
||||||
|
NavigationMenuTrigger,
|
||||||
|
} from "@/components/ui/navigation-menu";
|
||||||
|
import React from "react";
|
||||||
|
import { SearchBar } from "./serchBar";
|
||||||
|
import ListItem from "../listItem";
|
||||||
|
import { businessComponents, projectComponents, dataroomComponents } from "./menu";
|
||||||
|
import { ThemeToggle } from "../theme-toggle";
|
||||||
|
|
||||||
|
export function MobileMenu() {
|
||||||
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button onClick={() => setIsVisible((prev) => !prev)}>
|
||||||
|
<Menu />
|
||||||
|
</Button>
|
||||||
|
<AnimatePresence>
|
||||||
|
{isVisible && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ y: -100 }}
|
||||||
|
animate={{ y: 0 }}
|
||||||
|
exit={{ y: -100 }}
|
||||||
|
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||||
|
className="fixed top-0 left-0 w-full bg-white dark:bg-slate-900 border-b dark:border-slate-800 shadow-sm z-50"
|
||||||
|
>
|
||||||
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="flex items-center justify-between h-16">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsVisible(false)}
|
||||||
|
className="p-2 rounded-md hover:bg-slate-100 dark:hover:bg-slate-800"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<NavigationMenu>
|
||||||
|
<NavigationMenuList className="flex space-x-2">
|
||||||
|
<NavigationMenuItem>
|
||||||
|
<NavigationMenuTrigger className="text-sm font-medium">Businesses</NavigationMenuTrigger>
|
||||||
|
<NavigationMenuContent>
|
||||||
|
<ul className="w-[240px] p-4 gap-3">
|
||||||
|
{businessComponents.map((component) => (
|
||||||
|
<ListItem key={component.title} title={component.title} href={component.href}>
|
||||||
|
{component.description}
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</NavigationMenuContent>
|
||||||
|
</NavigationMenuItem>
|
||||||
|
|
||||||
|
<NavigationMenuItem>
|
||||||
|
<NavigationMenuTrigger className="text-sm font-medium">Projects</NavigationMenuTrigger>
|
||||||
|
<NavigationMenuContent>
|
||||||
|
<ul className="w-[240px] p-4 gap-3">
|
||||||
|
{projectComponents.map((component) => (
|
||||||
|
<ListItem key={component.title} title={component.title} href={component.href}>
|
||||||
|
{component.description}
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</NavigationMenuContent>
|
||||||
|
</NavigationMenuItem>
|
||||||
|
|
||||||
|
<NavigationMenuItem>
|
||||||
|
<NavigationMenuTrigger className="text-sm font-medium">Dataroom</NavigationMenuTrigger>
|
||||||
|
<NavigationMenuContent>
|
||||||
|
<ul className="w-[240px] p-4 gap-3">
|
||||||
|
{dataroomComponents.map((component) => (
|
||||||
|
<ListItem key={component.title} title={component.title} href={component.href}>
|
||||||
|
{component.description}
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</NavigationMenuContent>
|
||||||
|
</NavigationMenuItem>
|
||||||
|
</NavigationMenuList>
|
||||||
|
</NavigationMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center ml-2">
|
||||||
|
<SearchBar />
|
||||||
|
<div className="-ml-2">
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -2,7 +2,6 @@ import * as React from "react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { ThemeToggle } from "@/components/theme-toggle";
|
import { ThemeToggle } from "@/components/theme-toggle";
|
||||||
import {
|
import {
|
||||||
@ -21,31 +20,9 @@ import { createSupabaseClient } from "@/lib/supabase/serverComponentClient";
|
|||||||
import { getUserId } from "@/lib/supabase/actions/getUserId";
|
import { getUserId } from "@/lib/supabase/actions/getUserId";
|
||||||
import { getUnreadNotificationCountByUserId } from "@/lib/data/notificationQuery";
|
import { getUnreadNotificationCountByUserId } from "@/lib/data/notificationQuery";
|
||||||
|
|
||||||
import { MobileMenu } from "../mobileMenu";
|
import { MobileMenu } from "./mobileMenu";
|
||||||
|
import ListItem from "../listItem";
|
||||||
const ListItem = React.forwardRef<React.ElementRef<"a">, React.ComponentPropsWithoutRef<"a">>(
|
import { businessComponents, projectComponents, dataroomComponents } from "./menu";
|
||||||
({ className, title, children, ...props }, ref) => {
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<NavigationMenuLink asChild>
|
|
||||||
<a
|
|
||||||
ref={ref}
|
|
||||||
className={cn(
|
|
||||||
"block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<div className="text-sm font-medium leading-none">{title}</div>
|
|
||||||
<hr />
|
|
||||||
<p className="line-clamp-2 text-sm leading-snug text-muted-foreground">{children}</p>
|
|
||||||
</a>
|
|
||||||
</NavigationMenuLink>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
ListItem.displayName = "ListItem";
|
|
||||||
|
|
||||||
export async function NavigationBar() {
|
export async function NavigationBar() {
|
||||||
const client = createSupabaseClient();
|
const client = createSupabaseClient();
|
||||||
@ -59,30 +36,6 @@ export async function NavigationBar() {
|
|||||||
notification_count = 0;
|
notification_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const businessComponents = [
|
|
||||||
{
|
|
||||||
title: "Business",
|
|
||||||
href: "/business/apply",
|
|
||||||
description: "Apply to raise on on B2DVentures",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const projectComponents = [
|
|
||||||
{
|
|
||||||
title: "Projects",
|
|
||||||
href: "/project/apply",
|
|
||||||
description: "Start your new project on B2DVentures",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const dataroomComponents = [
|
|
||||||
{
|
|
||||||
title: "Overview",
|
|
||||||
href: "/dataroom/overview",
|
|
||||||
description: "View all dataroom available to you",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 flex flex-wrap w-full bg-card text-sm py-3 border-b-2 border-border z-50">
|
<header className="sticky top-0 flex flex-wrap w-full bg-card text-sm py-3 border-b-2 border-border z-50">
|
||||||
<nav className="max-w-screen-xl w-full mx-auto px-4">
|
<nav className="max-w-screen-xl w-full mx-auto px-4">
|
||||||
@ -93,15 +46,31 @@ export async function NavigationBar() {
|
|||||||
href="/"
|
href="/"
|
||||||
aria-label="Brand"
|
aria-label="Brand"
|
||||||
>
|
>
|
||||||
<span className="inline-flex items-center gap-x-2 text-xl font-semibold dark:text-white">
|
<span className="lg:inline-flex flex items-center gap-x-2 text-xl font-semibold dark:text-white">
|
||||||
<Image src="/logo.svg" alt="logo" width={50} height={50} />
|
<Image src="/logo.svg" alt="logo" width={50} height={50} className="w-10 h-10 sm:w-16 sm:h-16" />
|
||||||
B2DVentures
|
<span className="block lg:inline">
|
||||||
|
B2D<span className=" lg:inline">Ventures</span>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:hidden">
|
<div className="md:hidden grid grid-cols-2 justify-items-center items-center">
|
||||||
<MobileMenu />
|
<div className="flex justify-end w-10">
|
||||||
|
{userId ? (
|
||||||
|
<AuthenticatedComponents
|
||||||
|
uid={userId}
|
||||||
|
avatarUrl={avatarUrl?.avatar_url}
|
||||||
|
notificationCount={notification_count}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<UnAuthenticatedComponents />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="justify-end flex">
|
||||||
|
<MobileMenu />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="hidden md:flex items-center ">
|
<div className="hidden md:flex items-center ">
|
||||||
<NavigationMenu>
|
<NavigationMenu>
|
||||||
<NavigationMenuList>
|
<NavigationMenuList>
|
||||||
|
|||||||
@ -2,34 +2,100 @@
|
|||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Search } from "lucide-react";
|
import { Search, X } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
|
||||||
export function SearchBar() {
|
export function SearchBar() {
|
||||||
const [searchActive, setSearchActive] = React.useState(false);
|
const [searchActive, setSearchActive] = React.useState(false);
|
||||||
|
const [query, setQuery] = React.useState("");
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const handleKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
const handleKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
const query = (e.target as HTMLInputElement).value.trim();
|
const trimmedQuery = query.trim();
|
||||||
if (query) {
|
if (trimmedQuery) {
|
||||||
router.push(`/find?query=${encodeURIComponent(query)}`);
|
router.push(`/find?query=${encodeURIComponent(trimmedQuery)}`);
|
||||||
|
setSearchActive(false);
|
||||||
|
setQuery("");
|
||||||
}
|
}
|
||||||
|
} else if (e.key === "Escape") {
|
||||||
|
setSearchActive(false);
|
||||||
|
setQuery("");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle clicks outside of search bar
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
|
||||||
|
setSearchActive(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Focus input when search becomes active
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchActive && inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
}
|
||||||
|
}, [searchActive]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center">
|
<div
|
||||||
<Search onClick={() => setSearchActive(!searchActive)} className="cursor-pointer" />
|
ref={containerRef}
|
||||||
<input
|
className={cn(
|
||||||
type="text"
|
"relative flex items-center transition-all duration-300",
|
||||||
placeholder="Enter business name..."
|
searchActive &&
|
||||||
className={cn(
|
"fixed inset-0 bg-white/95 dark:bg-slate-900/95 z-50 px-4 md:relative md:bg-transparent md:dark:bg-transparent md:px-0"
|
||||||
"ml-2 border rounded-md px-2 py-1 transition-all duration-300 ease-in-out",
|
)}
|
||||||
searchActive ? "w-48 opacity-100" : "w-0 opacity-0"
|
>
|
||||||
)}
|
{/* Mobile overlay header when search is active */}
|
||||||
onKeyDown={handleKeyDown}
|
{searchActive && (
|
||||||
/>
|
<div className="absolute top-0 left-0 right-0 flex items-center p-4 md:hidden">
|
||||||
|
<X
|
||||||
|
className="w-6 h-6 cursor-pointer text-slate-600 dark:text-slate-400"
|
||||||
|
onClick={() => {
|
||||||
|
setSearchActive(false);
|
||||||
|
setQuery("");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className={cn("flex items-center w-full md:w-auto", searchActive ? "mt-16 md:mt-0" : "")}>
|
||||||
|
<Search
|
||||||
|
onClick={() => setSearchActive(!searchActive)}
|
||||||
|
className={cn(
|
||||||
|
"w-5 h-5 cursor-pointer transition-colors",
|
||||||
|
searchActive ? "text-blue-500" : "text-slate-600 dark:text-slate-400",
|
||||||
|
"md:hover:text-blue-500"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
value={query}
|
||||||
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
|
placeholder="Enter business name..."
|
||||||
|
className={cn(
|
||||||
|
"ml-2 rounded-md transition-all duration-300 ease-in-out outline-none",
|
||||||
|
"placeholder:text-slate-400 dark:placeholder:text-slate-500",
|
||||||
|
"bg-transparent md:bg-slate-100 md:dark:bg-slate-800",
|
||||||
|
"md:px-3 md:py-1.5",
|
||||||
|
searchActive
|
||||||
|
? "w-full opacity-100 border-b md:border md:w-48 lg:w-64 md:border-slate-200 md:dark:border-slate-700"
|
||||||
|
: "w-0 opacity-0 border-transparent"
|
||||||
|
)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export function SiteFooter() {
|
|||||||
Home
|
Home
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/about" className="hover:underline">
|
<Link href="/about" className="hover:underline">
|
||||||
About Us
|
About
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/privacy" className="hover:underline">
|
<Link href="/privacy" className="hover:underline">
|
||||||
Privacy
|
Privacy
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user