Skip to content

Commit 5422f9c

Browse files
committed
working on site layout
1 parent b983193 commit 5422f9c

23 files changed

+739
-6
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react";
2+
3+
const InviteBtn = () => {
4+
return <div>InviteBtn</div>;
5+
};
6+
7+
export default InviteBtn;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"use client";
2+
3+
import React from "react";
4+
import SearchInput from "./SearchInput";
5+
import { OrganizationSwitcher, UserButton } from "@clerk/nextjs";
6+
7+
const Navbar = () => {
8+
return (
9+
<div className="flex items-center gap-4 p-5">
10+
<div className="hidden lg:flex lg:flex-1">
11+
<SearchInput />
12+
</div>
13+
14+
<div className="block flex-1 lg:hidden">
15+
<OrganizationSwitcher
16+
hidePersonal
17+
appearance={{
18+
elements: {
19+
rootBox: {
20+
display: "flex",
21+
width: "100%",
22+
alignItems: "center",
23+
justifyContent: "center",
24+
maxWidth: "367px",
25+
},
26+
organizationSwitcherTrigger: {
27+
width: "100%",
28+
padding: "10px",
29+
borderRadius: "8px",
30+
border: "1px solid #E5E7EB",
31+
backgroundColor: "white",
32+
justifyContent: "space-between",
33+
maxWidth: "367px",
34+
},
35+
},
36+
}}
37+
/>
38+
</div>
39+
40+
<UserButton />
41+
</div>
42+
);
43+
};
44+
45+
export default Navbar;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"use client";
2+
3+
import React, { useEffect, useState } from "react";
4+
import qs from "query-string";
5+
import { Search, XIcon } from "lucide-react";
6+
import { useRouter } from "next/navigation";
7+
import { Input } from "@/components/ui/input";
8+
9+
const SearchInput = () => {
10+
const router = useRouter();
11+
12+
const [value, setValue] = useState("");
13+
14+
const [debounceValue, setDebounceValue] = useState("");
15+
16+
useEffect(() => {
17+
const timeout = setTimeout(() => {
18+
setDebounceValue(value);
19+
}, 500);
20+
21+
return () => {
22+
clearTimeout(timeout);
23+
};
24+
}, [value]);
25+
26+
useEffect(() => {
27+
const url = qs.stringifyUrl(
28+
{
29+
url: "/",
30+
query: {
31+
search: debounceValue,
32+
},
33+
},
34+
{ skipEmptyString: true, skipNull: true }
35+
);
36+
37+
router.push(url);
38+
}, [debounceValue, router]);
39+
40+
return (
41+
<div className="relative w-full max-w-[520px] flex items-center gap-3">
42+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
43+
44+
<Input
45+
className="w-full px-9"
46+
value={value}
47+
placeholder="Search Boards..."
48+
onChange={(e) => setValue(e.target.value)}
49+
/>
50+
51+
<XIcon
52+
className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground"
53+
onClick={() => setValue("")}
54+
/>
55+
</div>
56+
);
57+
};
58+
59+
export default SearchInput;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use client";
2+
3+
import React from "react";
4+
import Hint from "@/components/Hint";
5+
import { PlusIcon } from "lucide-react";
6+
import { CreateOrganization } from "@clerk/nextjs";
7+
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
8+
9+
const NewBtn = () => {
10+
return (
11+
<Dialog>
12+
<DialogTrigger>
13+
<div className="w-full aspect-square bg-white/20 flex items-center justify-center rounded-md opacity-75 hover:opacity-100 transition-opacity duration-150">
14+
<Hint
15+
label="Create Organization"
16+
side="right"
17+
align="start"
18+
sideOffset={15}
19+
>
20+
<PlusIcon />
21+
</Hint>
22+
</div>
23+
</DialogTrigger>
24+
25+
<DialogContent className="p-0 bg-transparent w-fit border-none">
26+
<CreateOrganization />
27+
</DialogContent>
28+
</Dialog>
29+
);
30+
};
31+
32+
export default NewBtn;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"use client";
2+
3+
import React from "react";
4+
import { cn } from "@/lib/utils";
5+
import Hint from "@/components/Hint";
6+
import { useOrganization, useOrganizationList } from "@clerk/nextjs";
7+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
8+
9+
type Props = {
10+
id: string;
11+
name: string;
12+
imageUrl: string;
13+
};
14+
15+
const OrgItem = ({ id, name, imageUrl }: Props) => {
16+
const { organization } = useOrganization();
17+
18+
const { setActive } = useOrganizationList();
19+
20+
const isActive = organization?.id === id;
21+
22+
const onClick = () => {
23+
if (!setActive) return;
24+
25+
setActive({ organization: id });
26+
};
27+
28+
return (
29+
<div className="w-full aspect-square">
30+
<Hint label={name} side="right" align="start" sideOffset={15}>
31+
<Avatar
32+
className={cn(
33+
"rounded-md opacity-75 hover:opacity-100 transition cursor-pointer overflow-hidden",
34+
isActive && "opacity-100"
35+
)}
36+
onClick={onClick}
37+
>
38+
<AvatarImage src={imageUrl} />
39+
40+
<AvatarFallback>{name[0]}</AvatarFallback>
41+
</Avatar>
42+
</Hint>
43+
</div>
44+
);
45+
};
46+
47+
export default OrgItem;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"use client";
2+
3+
import React from "react";
4+
import OrgItem from "./OrgItem";
5+
import { useOrganizationList } from "@clerk/nextjs";
6+
7+
const OrgList = () => {
8+
const { userMemberships } = useOrganizationList({
9+
userMemberships: {
10+
infinite: true,
11+
},
12+
});
13+
14+
if (userMemberships.data?.length === 0) {
15+
return null;
16+
}
17+
18+
return (
19+
<ul className="space-y-4">
20+
{userMemberships.data?.map((mem) => (
21+
<OrgItem
22+
key={mem.organization.id}
23+
id={mem.organization.id}
24+
name={mem.organization.name}
25+
imageUrl={mem.organization.imageUrl}
26+
/>
27+
))}
28+
</ul>
29+
);
30+
};
31+
32+
export default OrgList;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from "react";
2+
import NewBtn from "./NewBtn";
3+
import OrgList from "./OrgList";
4+
5+
const Sidebar = () => {
6+
return (
7+
<div className="fixed z-50 left-0 h-screen w-[60px] bg-blue-950 flex flex-col gap-4 text-white p-3">
8+
<OrgList />
9+
10+
<NewBtn />
11+
</div>
12+
);
13+
};
14+
15+
export default Sidebar;

app/(dashboard)/layout.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Navbar from "./_components/Navbar";
2+
import Sidebar from "./_components/sidebar";
3+
import OrgSidebar from "@/components/OrgSidebar";
4+
5+
export default function DashboardLayout({
6+
children,
7+
}: {
8+
children: React.ReactNode;
9+
}) {
10+
return (
11+
<main className="h-full">
12+
<Sidebar />
13+
14+
<div className="pl-[60px] h-full">
15+
<div className="h-full flex gap-3">
16+
<OrgSidebar />
17+
18+
<div className="h-full flex-1">
19+
<Navbar />
20+
21+
{children}
22+
</div>
23+
</div>
24+
</div>
25+
</main>
26+
);
27+
}
File renamed without changes.

bun.lockb

18.9 KB
Binary file not shown.

components/Hint.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from "react";
2+
import {
3+
Tooltip,
4+
TooltipContent,
5+
TooltipProvider,
6+
TooltipTrigger,
7+
} from "@/components/ui/tooltip";
8+
9+
type Props = {
10+
children: React.ReactNode;
11+
label: string;
12+
side?: "top" | "bottom" | "left" | "right";
13+
align?: "start" | "center" | "end";
14+
sideOffset?: number;
15+
allignOffset?: number;
16+
};
17+
18+
const Hint = ({
19+
children,
20+
label,
21+
side,
22+
align,
23+
sideOffset,
24+
allignOffset,
25+
}: Props) => {
26+
return (
27+
<TooltipProvider>
28+
<Tooltip delayDuration={100}>
29+
<TooltipTrigger asChild>{children}</TooltipTrigger>
30+
31+
<TooltipContent
32+
className="text-white bg-black/75"
33+
side={side}
34+
align={align}
35+
sideOffset={sideOffset}
36+
alignOffset={allignOffset}
37+
>
38+
<p className="font-semibold capitalize">{label}</p>
39+
</TooltipContent>
40+
</Tooltip>
41+
</TooltipProvider>
42+
);
43+
};
44+
45+
export default Hint;

0 commit comments

Comments
 (0)