Skip to content

Commit

Permalink
Feature/UI cleanup (Codehagen#208)
Browse files Browse the repository at this point in the history
* main nav refactor

* WIP

* refactor: move page around

* fix: mobile ui

* refactor: remove useless dep + fix clerk console error
  • Loading branch information
matteobad authored Mar 12, 2024
1 parent c0a7fd6 commit 6550a1c
Show file tree
Hide file tree
Showing 205 changed files with 1,866 additions and 6,249 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ cp .env.example .env.local
2. Create [Planet Scale](https://planetscale.com/) Account
3. Create [Resend](https://resend.com) Account
4. Create [Stripe](https://stripe.com) Account and download [Stripe CLI](https://docs.stripe.com/stripe-cli)
5. Create [Edge Store](https://edgestore.dev) Account
6. Secure [CRON](https://dev.to/chrisnowicki/how-to-secure-vercel-cron-job-routes-in-nextjs-13-9g8) jobs
5. Secure [CRON](https://dev.to/chrisnowicki/how-to-secure-vercel-cron-job-routes-in-nextjs-13-9g8) jobs

5. Start the development server from either yarn or turbo:

Expand Down Expand Up @@ -151,7 +150,6 @@ The default setting for `TEST_EMAIL_ADDRESS` is `delivered@resend.dev` but you h
- [Vercel](https://vercel.com/) – Easily preview & deploy changes with git
- [PlanetScale](https://planetscale.com/) – A cutting-edge database platform for seamless, scalable data management
- [Resend](https://resend.com/) – A powerful email framework for streamlined email development
- [Edge Store](https://edgestore.dev/) - Storage, CDN and a super easy to use type-safe library.
- [Stripe](https://stripe.com) - Payments

### UI
Expand Down
20 changes: 0 additions & 20 deletions apps/www/actions/send-onboarding-email.ts

This file was deleted.

124 changes: 124 additions & 0 deletions apps/www/app/(dashboard)/(workspaceId)/_components/sidebar-nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import Link from "next/link";
import { useParams, usePathname } from "next/navigation";

import { cn } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
import { buttonVariants } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { NavItem, sideNavItems } from "@/app/config";

import { WorkspaceSwitcher } from "../../_components/workspace-switcher";

const CollapsedItem = ({
item,
currentPath,
}: {
item: NavItem;
currentPath: string;
}) => {
return (
<Tooltip delayDuration={0}>
<TooltipTrigger asChild>
<Link
href={item.href}
className={cn(
buttonVariants({ variant: "ghost", size: "icon" }),
"h-9 w-9",
currentPath === item.href
? "bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
: "transparent",
"soon" === item.badge && "cursor-not-allowed opacity-80",
)}
>
{item.icon && <item.icon className="h-4 w-4" />}
<span className="sr-only">{item.title}</span>
</Link>
</TooltipTrigger>
<TooltipContent side="right" className="flex items-center gap-4">
{item.title}
{item?.badge ? <Badge>Coming soon</Badge> : null}
</TooltipContent>
</Tooltip>
);
};

const ExpandedItem = ({
item,
currentPath,
}: {
item: NavItem;
currentPath: string;
}) => {
return (
<Link
href={item.href}
className={cn(
buttonVariants({ variant: "ghost", size: "sm" }),
"justify-start",
currentPath === item.href
? "bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
: "transparent",
"soon" === item.badge && "cursor-not-allowed opacity-80",
)}
>
{item.icon && <item.icon className="mr-2 h-4 w-4" />}
{item.title}
<span className={cn("ml-auto")}>
{item?.badge && <Badge>{item.badge}</Badge>}
</span>
</Link>
);
};

// TODO: idx not needed as key when all items have unique hrefs
// also, the active link should be filtered by href and not idx
export function SidebarNav({ isCollapsed }: { isCollapsed: boolean }) {
const params = useParams<{ workspaceId: string }>();
const path = usePathname();

// remove the workspaceId from the path when comparing active links in sidebar
const pathname = path.replace(`/${params.workspaceId}`, "") || "/";
const [_, currentPath] = pathname.split("/");

return (
<nav
className={cn("flex flex-col", {
"items-center justify-center": isCollapsed,
})}
>
<div className="p-2">
<WorkspaceSwitcher isCollapsed={isCollapsed} />
</div>

{sideNavItems.map((group) => {
return (
<>
<Separator />
<div className="flex flex-col gap-1 p-2" key={group.group}>
{group.items.map((link, idx) => {
return isCollapsed ? (
<CollapsedItem
key={link.href + idx}
item={link}
currentPath={"/" + currentPath}
/>
) : (
<ExpandedItem
key={link.href + idx}
item={link}
currentPath={"/" + currentPath}
/>
);
})}
</div>
</>
);
})}
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"use client";

import * as React from "react";

import { ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { TooltipProvider } from "@/components/ui/tooltip";

import { Mail } from "../data";
import { useMail } from "../use-mail";
import { SankeyCard } from "./sankey-card";
import { CardsStats } from "./stats";

interface DashboardProps {
accounts: {
label: string;
email: string;
icon: React.ReactNode;
}[];
mails: Mail[];
defaultLayout: number[] | undefined;
defaultCollapsed?: boolean;
navCollapsedSize: number;
}

export function SaveMoneyDashboard({
accounts,
mails,
defaultLayout = [265, 440, 655],
defaultCollapsed = false,
navCollapsedSize,
}: DashboardProps) {
const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed);
const [mail] = useMail();

return (
<TooltipProvider delayDuration={0}>
<ResizablePanelGroup
direction="horizontal"
onLayout={(sizes: number[]) => {
document.cookie = `react-resizable-panels:layout=${JSON.stringify(
sizes,
)}`;
}}
className="h-full max-h-[1200px] items-stretch"
>
<ResizablePanel defaultSize={defaultLayout[1]} minSize={30}>
<ScrollArea className="h-screen">
<div className="flex h-[52px] items-center px-4 py-2">
<h1 className="text-xl font-bold">Dashboard</h1>
</div>
<Separator />

<div className="bg-background/95 p-4 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<form></form>
</div>
<SankeyCard />
<CardsStats />
{/* <div className="ml-6 mt-6 flex gap-4"> */}
<div className="mx-6 mt-6 grid gap-4 sm:grid-cols-2 xl:grid-cols-2">
{/* <TransactionsReviewTable />
<TopCategoriesTable /> */}
</div>
</ScrollArea>
</ResizablePanel>
</ResizablePanelGroup>
</TooltipProvider>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"use client";

import * as React from "react";
import { BoltIcon } from "@heroicons/react/20/solid";
import {
ColumnDef,
ColumnFiltersState,
Expand All @@ -15,6 +14,7 @@ import {
VisibilityState,
} from "@tanstack/react-table";
import {
BoltIcon,
CarIcon,
CoffeeIcon,
HomeIcon,
Expand Down
File renamed without changes.
24 changes: 24 additions & 0 deletions apps/www/app/(dashboard)/(workspaceId)/aimagic/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NavItem } from "@/app/config";

import { DashboardShell } from "../../_components/dashboard-shell";

export default function WorkspaceLayout(props: {
children: React.ReactNode;
params: { workspaceId: string };
}) {
return (
<>
<DashboardShell
title="AI Magic"
description="Projects for this workspace will show up here"
// headerAction={
// <AddAssetButton triggerLabel="Add Asset">
// <AddAssetFlow />
// </AddAssetButton>
// }
>
{props.children}
</DashboardShell>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { cookies } from "next/headers";

import { accounts, mails } from "@/components/new-dashboard/data";
import { AiMagicDashboard } from "@/components/savemoney/components/ai-magic-dashboard";
import { AiMagicDashboard } from "../savings/_components/ai-magic-dashboard";
import { accounts, mails } from "./data";

export const metadata = {
title: "Dasboard",
description: "Dashboard description",
title: "AI Magic",
description: "AI Magic description",
};

export default async function DashboardPage() {
export default async function AIMagicPage() {
const layout = cookies().get("react-resizable-panels:layout");
const collapsed = cookies().get("react-resizable-panels:collapsed");

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"use client";

import * as React from "react";
import { Search } from "lucide-react";

import { Input } from "@/components/ui/input";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { TooltipProvider } from "@/components/ui/tooltip";

import { Mail } from "../data";
import { useMail } from "../use-mail";
import { AccountsDisplay } from "./accounts-display";
import { AccountsList } from "./accounts-list";

interface AccountsDashboardProps {
mails: Mail[];
defaultLayout: number[] | undefined;
}

export function AccountsDashboard({
mails,
defaultLayout = [20, 40, 40],
}: AccountsDashboardProps) {
const [mail] = useMail();

return (
<TooltipProvider delayDuration={0}>
<ResizablePanelGroup
direction="horizontal"
onLayout={(sizes: number[]) => {
document.cookie = `react-resizable-panels:layout-accounts=${JSON.stringify(
sizes,
)}`;
}}
className="h-full max-h-[1200px] items-stretch"
>
<ResizablePanel defaultSize={defaultLayout[1]} minSize={30}>
<Tabs defaultValue="all">
<div className="flex items-center justify-between gap-4 px-4 py-2">
<form className="flex-1">
<div className="relative">
<Search className="absolute left-2 top-3 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search" className="pl-8" />
</div>
</form>
<TabsList className="ml-auto">
<TabsTrigger
value="all"
className="text-zinc-600 dark:text-zinc-200"
>
All accounts
</TabsTrigger>
<TabsTrigger
value="unread"
className="text-zinc-600 dark:text-zinc-200"
>
New accounts
</TabsTrigger>
</TabsList>
</div>
<Separator />
<TabsContent value="all" className="m-0">
<AccountsList items={mails} />
</TabsContent>
<TabsContent value="unread" className="m-0">
<AccountsList items={mails.filter((item) => !item.read)} />
</TabsContent>
</Tabs>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={defaultLayout[2]}>
<AccountsDisplay
mail={mails.find((item) => item.id === mail.selected) || null}
/>
</ResizablePanel>
</ResizablePanelGroup>
</TooltipProvider>
);
}
Loading

0 comments on commit 6550a1c

Please sign in to comment.