Skip to content

Commit 134d967

Browse files
authored
Merge pull request #351 from mfts/feat/folders
feat: folders
2 parents fceb0d9 + cb05105 commit 134d967

File tree

24 files changed

+2011
-316
lines changed

24 files changed

+2011
-316
lines changed

components/Sidebar.tsx

Lines changed: 134 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useEffect, useState } from "react";
22
import { useSession } from "next-auth/react";
3-
import FolderIcon from "@/components/shared/icons/folder";
43
import SettingsIcon from "@/components/shared/icons/settings";
54
import MenuIcon from "@/components/shared/icons/menu";
65
import { cn } from "@/lib/utils";
@@ -15,7 +14,16 @@ import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
1514
import ProfileMenu from "./profile-menu";
1615
import { AddDocumentModal } from "./documents/add-document-modal";
1716
import { Button } from "./ui/button";
18-
import { PaletteIcon, PlusIcon } from "lucide-react";
17+
import {
18+
FolderPlusIcon,
19+
PaletteIcon,
20+
PlusIcon,
21+
FolderIcon as FolderLucideIcon,
22+
FolderOpenIcon,
23+
} from "lucide-react";
24+
import SiderbarFolders from "./sidebar-folders";
25+
import { AddFolderModal } from "./documents/add-folder-modal";
26+
import { ScrollArea } from "./ui/scroll-area";
1927

2028
export default function Sidebar() {
2129
return (
@@ -80,15 +88,21 @@ export const SidebarComponent = ({ className }: { className?: string }) => {
8088
{
8189
name: "Documents",
8290
href: "/documents",
83-
icon: FolderIcon,
84-
current: router.pathname.includes("documents"),
91+
icon: router.pathname.includes("documents")
92+
? FolderOpenIcon
93+
: FolderLucideIcon,
94+
current:
95+
router.pathname.includes("documents") &&
96+
!router.pathname.includes("tree"),
97+
active: router.pathname.includes("documents"),
8598
disabled: false,
8699
},
87100
{
88101
name: "Branding",
89102
href: "/settings/branding",
90103
icon: PaletteIcon,
91104
current: router.pathname.includes("branding"),
105+
active: false,
92106
disabled: false,
93107
},
94108
{
@@ -98,82 +112,133 @@ export const SidebarComponent = ({ className }: { className?: string }) => {
98112
current:
99113
router.pathname.includes("settings") &&
100114
!router.pathname.includes("branding"),
115+
active: false,
101116
disabled: false,
102117
},
103118
];
104119

105120
return (
106-
<aside
107-
className={cn(
108-
"w-full h-screen lg:w-72 flex-shrink-0 flex-col justify-between gap-y-6 bg-gray-50 dark:bg-black px-4 lg:px-6 pt-4 lg:pt-6",
109-
className,
110-
)}
111-
>
112-
{/* Sidebar component, swap this element with another sidebar if you like */}
113-
114-
<div className="flex h-16 shrink-0 items-center space-x-3">
115-
<p className="text-2xl font-bold tracking-tighter text-black dark:text-white flex items-center">
116-
Papermark{" "}
117-
{userPlan == "pro" ? (
118-
<span className="bg-background text-foreground ring-1 ring-gray-800 rounded-full px-2.5 py-1 text-xs ml-4">
119-
Pro
120-
</span>
121-
) : null}
122-
</p>
123-
</div>
121+
<div>
122+
<aside
123+
className={cn(
124+
"w-full h-screen lg:w-72 flex-shrink-0 flex-col justify-between gap-y-6 bg-gray-50 dark:bg-black px-4 lg:px-6 pt-4 lg:pt-6",
125+
className,
126+
)}
127+
>
128+
{/* Sidebar component, swap this element with another sidebar if you like */}
124129

125-
<SelectTeam
126-
currentTeam={currentTeam}
127-
teams={teams}
128-
isLoading={isLoading}
129-
setCurrentTeam={() => {}}
130-
/>
130+
<div className="flex h-16 shrink-0 items-center space-x-3">
131+
<p className="text-2xl font-bold tracking-tighter text-black dark:text-white flex items-center">
132+
Papermark{" "}
133+
{userPlan == "pro" ? (
134+
<span className="bg-background text-foreground ring-1 ring-gray-800 rounded-full px-2.5 py-1 text-xs ml-4">
135+
Pro
136+
</span>
137+
) : null}
138+
</p>
139+
</div>
131140

132-
<AddDocumentModal>
133-
<Button
134-
className="w-full text-left group flex gap-x-3 items-center justify-start px-3"
135-
title="Add New Document"
136-
>
137-
<PlusIcon className="h-5 w-5 shrink-0" aria-hidden="true" />
138-
<span>Add New Document</span>
139-
</Button>
140-
</AddDocumentModal>
141+
<SelectTeam
142+
currentTeam={currentTeam}
143+
teams={teams}
144+
isLoading={isLoading}
145+
setCurrentTeam={() => {}}
146+
/>
141147

142-
<section className="flex flex-1 flex-col gap-y-6">
143-
<div className="space-y-2">
144-
{navigation.map((item) => (
145-
<button
146-
key={item.name}
147-
onClick={() => router.push(item.href)}
148-
disabled={item.disabled}
149-
className={cn(
150-
item.current
151-
? "bg-gray-200 dark:bg-secondary text-secondary-foreground font-semibold"
152-
: "text-muted-foreground hover:text-foreground hover:bg-gray-200 hover:dark:bg-muted duration-200",
153-
"group flex gap-x-3 items-center rounded-md px-3 py-2 text-sm leading-6 w-full disabled:hover:bg-transparent disabled:text-muted-foreground disabled:cursor-default",
154-
)}
148+
<div className="flex items-center gap-x-1">
149+
<AddDocumentModal>
150+
<Button
151+
className="flex-1 text-left group flex gap-x-3 items-center justify-start px-3"
152+
title="Add New Document"
153+
>
154+
<PlusIcon className="h-5 w-5 shrink-0" aria-hidden="true" />
155+
<span>Add New Document</span>
156+
</Button>
157+
</AddDocumentModal>
158+
<AddFolderModal>
159+
<Button
160+
size="icon"
161+
variant="outline"
162+
className="bg-gray-50 dark:bg-black border-gray-500 hover:bg-gray-200 hover:dark:bg-muted"
155163
>
156-
<item.icon className="h-5 w-5 shrink-0" aria-hidden="true" />
157-
{item.name}
158-
</button>
159-
))}
164+
<FolderPlusIcon className="w-5 h-5 shrink-0" aria-hidden="true" />
165+
</Button>
166+
</AddFolderModal>
160167
</div>
161-
</section>
162-
<div className="mb-4">
163-
{/* if user is on trial show banner,
164-
* if user is pro show nothing,
165-
* if user is free and showProBanner is true show pro banner
166-
*/}
167-
{userPlan === "trial" && session ? <Banner session={session} /> : null}
168-
{userPlan === "pro" && null}
169-
{userPlan === "free" && showProBanner ? (
170-
<ProBanner setShowProBanner={setShowProBanner} />
171-
) : null}
172168

173-
<div className="w-full hidden lg:block">
174-
<ProfileMenu size="large" />
169+
<ScrollArea className="flex-grow" showScrollbar>
170+
<section className="flex flex-1 flex-col gap-y-6">
171+
<div className="space-y-2">
172+
{navigation.map((item) => {
173+
if (item.name === "Documents") {
174+
return (
175+
<>
176+
<button
177+
key={item.name}
178+
onClick={() => router.push(item.href)}
179+
disabled={item.disabled}
180+
className={cn(
181+
item.current
182+
? "bg-gray-200 dark:bg-secondary text-secondary-foreground font-semibold"
183+
: "text-muted-foreground hover:text-foreground hover:bg-gray-200 hover:dark:bg-muted duration-200",
184+
router.pathname.includes("documents") &&
185+
"text-foreground",
186+
"group flex gap-x-2 items-center rounded-md px-3 py-2 text-sm leading-6 w-full disabled:hover:bg-transparent disabled:text-muted-foreground disabled:cursor-default",
187+
)}
188+
>
189+
<item.icon
190+
className="h-5 w-5 shrink-0"
191+
aria-hidden="true"
192+
/>
193+
{item.name}
194+
</button>
195+
{item.active ? <SiderbarFolders /> : null}
196+
</>
197+
);
198+
}
199+
return (
200+
<button
201+
key={item.name}
202+
onClick={() => router.push(item.href)}
203+
disabled={item.disabled}
204+
className={cn(
205+
item.current
206+
? "bg-gray-200 dark:bg-secondary text-secondary-foreground font-semibold"
207+
: "text-muted-foreground hover:text-foreground hover:bg-gray-200 hover:dark:bg-muted duration-200",
208+
router.pathname.includes("documents") &&
209+
"text-foreground",
210+
"group flex gap-x-2 items-center rounded-md px-3 py-2 text-sm leading-6 w-full disabled:hover:bg-transparent disabled:text-muted-foreground disabled:cursor-default",
211+
)}
212+
>
213+
<item.icon
214+
className="h-5 w-5 shrink-0"
215+
aria-hidden="true"
216+
/>
217+
{item.name}
218+
</button>
219+
);
220+
})}
221+
</div>
222+
</section>
223+
</ScrollArea>
224+
<div className="mb-4">
225+
{/* if user is on trial show banner,
226+
* if user is pro show nothing,
227+
* if user is free and showProBanner is true show pro banner
228+
*/}
229+
{userPlan === "trial" && session ? (
230+
<Banner session={session} />
231+
) : null}
232+
{userPlan === "pro" && null}
233+
{userPlan === "free" && showProBanner ? (
234+
<ProBanner setShowProBanner={setShowProBanner} />
235+
) : null}
236+
237+
<div className="w-full hidden lg:block">
238+
<ProfileMenu size="large" />
239+
</div>
175240
</div>
176-
</div>
177-
</aside>
241+
</aside>
242+
</div>
178243
);
179244
};

components/documents/add-document-modal.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export function AddDocumentModal({
4343

4444
const teamId = teamInfo?.currentTeam?.id as string;
4545

46+
/** current folder name */
47+
const currentFolderPath = router.query.name as string[] | undefined;
48+
4649
const handleFileUpload = async (
4750
event: FormEvent<HTMLFormElement>,
4851
): Promise<void> => {
@@ -71,7 +74,12 @@ export function AddDocumentModal({
7174
// create a document or new version in the database
7275
if (!newVersion) {
7376
// create a document in the database
74-
response = await createDocument({ documentData, teamId, numPages });
77+
response = await createDocument({
78+
documentData,
79+
teamId,
80+
numPages,
81+
folderPathName: currentFolderPath?.join("/"),
82+
});
7583
} else {
7684
// create a new version for existing document in the database
7785
const documentId = router.query.id as string;

0 commit comments

Comments
 (0)