-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
629 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const LAYOUT_TRANSITIONS = { | ||
duration: 0.4, | ||
ease: "easeInOut", | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
"use client"; | ||
|
||
import { PropsWithChildren } from "react"; | ||
|
||
import { LayoutGroup } from "framer-motion"; | ||
|
||
import MainNav from "@/containers/nav"; | ||
|
||
export default function BlueCarbonCostLayout({ children }: PropsWithChildren) { | ||
return ( | ||
<main className="flex h-dvh overflow-hidden"> | ||
<LayoutGroup> | ||
<MainNav /> | ||
{children} | ||
</LayoutGroup> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
"use client"; | ||
|
||
import { motion } from "framer-motion"; | ||
import { useAtomValue } from "jotai"; | ||
|
||
import { LAYOUT_TRANSITIONS } from "@/app/(projects)/constants"; | ||
import { projectsUIState } from "@/app/(projects)/store"; | ||
|
||
import ProjectsFilters from "@/containers/projects/filters"; | ||
import ProjectsHeader from "@/containers/projects/header"; | ||
import ProjectsMap from "@/containers/projects/map"; | ||
import ProjectsTable from "@/containers/projects/table"; | ||
|
||
export default function Projects() { | ||
const { navOpen, filtersOpen, mapExpanded, tableExpanded } = | ||
useAtomValue(projectsUIState); | ||
|
||
return ( | ||
<motion.div | ||
layout | ||
layoutDependency={navOpen} | ||
className="flex flex-1" | ||
transition={LAYOUT_TRANSITIONS} | ||
> | ||
<motion.aside | ||
layout | ||
initial={filtersOpen ? "open" : "closed"} | ||
animate={filtersOpen ? "open" : "closed"} | ||
variants={{ | ||
open: { | ||
width: 450, | ||
}, | ||
closed: { | ||
width: 0, | ||
}, | ||
}} | ||
transition={LAYOUT_TRANSITIONS} | ||
className="overflow-hidden" | ||
> | ||
<ProjectsFilters /> | ||
</motion.aside> | ||
<div className="flex flex-1 flex-col"> | ||
<ProjectsHeader /> | ||
<div className="grid flex-grow grid-rows-2"> | ||
<motion.section | ||
layout | ||
// initial={mapExpanded ? "expanded" : "collapsed"} | ||
initial={{ | ||
height: "auto", | ||
}} | ||
animate={mapExpanded ? "expanded" : "collapsed"} | ||
variants={{ | ||
expanded: { | ||
height: "100%", | ||
}, | ||
collapsed: { | ||
height: 0, | ||
}, | ||
}} | ||
transition={LAYOUT_TRANSITIONS} | ||
> | ||
<ProjectsMap /> | ||
</motion.section> | ||
<motion.section | ||
layout | ||
initial={tableExpanded ? "expanded" : "collapsed"} | ||
animate={tableExpanded ? "expanded" : "collapsed"} | ||
variants={{ | ||
expanded: { | ||
height: "100%", | ||
}, | ||
collapsed: { | ||
height: 0, | ||
}, | ||
}} | ||
transition={LAYOUT_TRANSITIONS} | ||
> | ||
<ProjectsTable /> | ||
</motion.section> | ||
</div> | ||
</div> | ||
</motion.div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { atom } from "jotai"; | ||
|
||
export const mainNavOpenAtom = atom(false); | ||
export const filtersProjectOpenAtom = atom(false); | ||
|
||
export const mapExpandedAtom = atom(false); | ||
export const tableExpandedAtom = atom(false); | ||
|
||
export const projectsUIState = atom({ | ||
navOpen: false, | ||
filtersOpen: false, | ||
mapExpanded: false, | ||
tableExpanded: false, | ||
}); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
"use client"; | ||
|
||
import Link from "next/link"; | ||
|
||
import { motion } from "framer-motion"; | ||
import { useAtom } from "jotai"; | ||
import { ActivityIcon, ChevronRight, ChevronLeft } from "lucide-react"; | ||
|
||
import { LAYOUT_TRANSITIONS } from "@/app/(projects)/constants"; | ||
import { projectsUIState } from "@/app/(projects)/store"; | ||
|
||
import { MainNavItem } from "@/containers/nav/item"; | ||
|
||
export default function MainNav() { | ||
const [{ navOpen }, setUIState] = useAtom(projectsUIState); | ||
|
||
return ( | ||
<motion.nav | ||
layout="size" | ||
layoutDependency={navOpen} | ||
transition={LAYOUT_TRANSITIONS} | ||
className="pointer-events-auto relative z-10 h-full overflow-hidden" | ||
> | ||
<div className="relative z-20 flex h-full flex-col justify-between bg-white px-4 py-6"> | ||
<motion.div | ||
layout="position" | ||
className="divide-navy-100 flex flex-col divide-y" | ||
> | ||
<div className="flex flex-col items-start pb-3"> | ||
<Link href="/" className="flex flex-col items-center space-y-1"> | ||
<div className="relative flex h-10 w-10 flex-col items-center space-y-1"> | ||
<motion.span | ||
initial={"initial"} | ||
animate={navOpen ? "animate" : "initial"} | ||
variants={{ | ||
initial: { opacity: 0 }, | ||
animate: { opacity: 1 }, | ||
}} | ||
className="absolute -top-1 left-full block translate-x-0.5 text-[7px] font-bold uppercase leading-[8px] opacity-0" | ||
> | ||
Blue Carbon Cost | ||
</motion.span> | ||
</div> | ||
</Link> | ||
</div> | ||
|
||
<MainNavItem href="/" label="High level projects" index={0}> | ||
<ActivityIcon /> | ||
</MainNavItem> | ||
|
||
<ul className="space-y-3 py-3"> | ||
<li> | ||
<MainNavItem | ||
href="/projects/new" | ||
label="New custom projects" | ||
index={1} | ||
> | ||
<ActivityIcon /> | ||
</MainNavItem> | ||
</li> | ||
<ul> | ||
<li> | ||
<MainNavItem | ||
href="/projects/custom" | ||
label="Custom projects" | ||
index={2} | ||
> | ||
<ActivityIcon /> | ||
</MainNavItem> | ||
</li> | ||
</ul> | ||
</ul> | ||
</motion.div> | ||
<motion.div | ||
layout="position" | ||
className="divide-navy-100 flex flex-col divide-y" | ||
> | ||
<ul className="space-y-3 py-3"> | ||
<MainNavItem href="/atlas/login" label="User profile" index={6}> | ||
<ActivityIcon className="h-5 w-5" /> | ||
</MainNavItem> | ||
</ul> | ||
|
||
<ul className="space-y-3 py-3"> | ||
<MainNavItem label="Help center" href="/methodology" index={7}> | ||
<ActivityIcon className="h-5 w-5" /> | ||
</MainNavItem> | ||
</ul> | ||
|
||
<ul className="space-y-3 py-3"> | ||
<MainNavItem | ||
label={navOpen ? "Collapse side menu" : "Expand side menu"} | ||
onClick={() => | ||
setUIState((prev) => ({ | ||
...prev, | ||
navOpen: !prev.navOpen, | ||
})) | ||
} | ||
index={8} | ||
> | ||
{!navOpen && <ChevronRight className="h-5 w-5" />} | ||
{navOpen && <ChevronLeft className="h-5 w-5" />} | ||
</MainNavItem> | ||
</ul> | ||
</motion.div> | ||
</div> | ||
</motion.nav> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
"use client"; | ||
import { ButtonHTMLAttributes } from "react"; | ||
|
||
import Link from "next/link"; | ||
import { usePathname } from "next/navigation"; | ||
|
||
import { TooltipPortal } from "@radix-ui/react-tooltip"; | ||
import { motion } from "framer-motion"; | ||
import { useAtomValue } from "jotai"; | ||
|
||
import { cn } from "@/lib/utils"; | ||
|
||
import { mainNavOpenAtom } from "@/app/(projects)/store"; | ||
|
||
import { | ||
Tooltip, | ||
TooltipContent, | ||
TooltipTrigger, | ||
} from "@/components/ui/tooltip"; | ||
|
||
export const MainNavItem = ({ | ||
index, | ||
label, | ||
href, | ||
children, | ||
...props | ||
}: ButtonHTMLAttributes<HTMLButtonElement> & { | ||
index: number; | ||
label: string; | ||
href?: string; | ||
children: React.ReactNode; | ||
}) => { | ||
// const searchParams = useSyncSearchParams(); | ||
|
||
const navOpen = useAtomValue(mainNavOpenAtom); | ||
// const [sidebarOpen, setSidebarOpen] = useAtom(sidebarOpenAtom); | ||
const pathname = usePathname(); | ||
|
||
return ( | ||
<Tooltip delayDuration={100} open={navOpen ? false : undefined}> | ||
{href && ( | ||
<TooltipTrigger asChild> | ||
<Link | ||
// href={`${href}${searchParams}`} | ||
href={href} | ||
prefetch | ||
className={cn({ | ||
"flex items-center gap-3 rounded-sm p-2.5": true, | ||
"text-navy-500 hover:bg-lightblue-50": pathname !== href, | ||
"bg-lightblue-100 text-navy-700": | ||
(href !== "/" && pathname.includes(href)) || pathname === href, | ||
})} | ||
// onClick={() => { | ||
// const open = pathname !== href ? true : !sidebarOpen; | ||
// setSidebarOpen(open); | ||
// }} | ||
> | ||
{children} | ||
|
||
{navOpen && ( | ||
<motion.span | ||
className="text-nowrap text-sm leading-none" | ||
initial={{ opacity: 0, x: -10 }} | ||
animate={{ opacity: 1, x: 0 }} | ||
transition={{ duration: 0.2, delay: index * 0.05 }} | ||
> | ||
{label} | ||
</motion.span> | ||
)} | ||
</Link> | ||
</TooltipTrigger> | ||
)} | ||
|
||
{!href && ( | ||
<TooltipTrigger asChild> | ||
<button | ||
className="flex items-center gap-4 rounded-sm p-2.5" | ||
{...props} | ||
> | ||
{children} | ||
|
||
{navOpen && ( | ||
<motion.span | ||
className="text-nowrap text-sm leading-none" | ||
initial={{ opacity: 0, x: -10 }} | ||
animate={{ opacity: 1, x: 0 }} | ||
transition={{ duration: 0.2, delay: index * 0.05 }} | ||
> | ||
{label} | ||
</motion.span> | ||
)} | ||
</button> | ||
</TooltipTrigger> | ||
)} | ||
<TooltipPortal> | ||
<TooltipContent side="right">{label}</TooltipContent> | ||
</TooltipPortal> | ||
</Tooltip> | ||
); | ||
}; |
Oops, something went wrong.