diff --git a/app/actions.ts b/app/actions.ts
index dbf8a26..d02e6ce 100644
--- a/app/actions.ts
+++ b/app/actions.ts
@@ -4,6 +4,8 @@ import { encodedRedirect } from "@/utils/utils";
import { createClient } from "@/utils/supabase/server";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
+import { Provider } from "@supabase/supabase-js";
+import { revalidatePath } from "next/cache";
export const signUpAction = async (formData: FormData) => {
const email = formData.get("email")?.toString();
@@ -12,11 +14,7 @@ export const signUpAction = async (formData: FormData) => {
const origin = (await headers()).get("origin");
if (!email || !password) {
- return encodedRedirect(
- "error",
- "/sign-up",
- "Email and password are required",
- );
+ return encodedRedirect("error", "/login", "Email is required");
}
const { error } = await supabase.auth.signUp({
@@ -34,26 +32,47 @@ export const signUpAction = async (formData: FormData) => {
return encodedRedirect(
"success",
"/sign-up",
- "Thanks for signing up! Please check your email for a verification link.",
+ "Thanks for signing up! Please check your email for a verification link."
);
}
};
export const signInAction = async (formData: FormData) => {
const email = formData.get("email") as string;
- const password = formData.get("password") as string;
+ const provider = formData.get("provider") as Provider;
const supabase = await createClient();
+ if (email) {
+ const { error } = await supabase.auth.signInWithOtp({
+ email,
+ options: {
+ emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
+ },
+ });
- const { error } = await supabase.auth.signInWithPassword({
- email,
- password,
- });
+ if (error) {
+ return encodedRedirect("error", "/login", error.message);
+ }
+ } else if (provider) {
+ const { error, data } = await supabase.auth.signInWithOAuth({
+ provider,
+ options: {
+ redirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
+ },
+ });
- if (error) {
- return encodedRedirect("error", "/sign-in", error.message);
+ if (error) {
+ return encodedRedirect("error", "/login", error.message);
+ }
+
+ if (data?.url) {
+ return redirect(data.url);
+ } else {
+ return encodedRedirect("error", "/login", "Could not sign in");
+ }
}
- return redirect("/protected");
+ revalidatePath("/", "layout");
+ redirect("/dashboard");
};
export const forgotPasswordAction = async (formData: FormData) => {
@@ -75,7 +94,7 @@ export const forgotPasswordAction = async (formData: FormData) => {
return encodedRedirect(
"error",
"/forgot-password",
- "Could not reset password",
+ "Could not reset password"
);
}
@@ -86,7 +105,7 @@ export const forgotPasswordAction = async (formData: FormData) => {
return encodedRedirect(
"success",
"/forgot-password",
- "Check your email for a link to reset your password.",
+ "Check your email for a link to reset your password."
);
};
@@ -100,7 +119,7 @@ export const resetPasswordAction = async (formData: FormData) => {
encodedRedirect(
"error",
"/protected/reset-password",
- "Password and confirm password are required",
+ "Password and confirm password are required"
);
}
@@ -108,7 +127,7 @@ export const resetPasswordAction = async (formData: FormData) => {
encodedRedirect(
"error",
"/protected/reset-password",
- "Passwords do not match",
+ "Passwords do not match"
);
}
@@ -120,7 +139,7 @@ export const resetPasswordAction = async (formData: FormData) => {
encodedRedirect(
"error",
"/protected/reset-password",
- "Password update failed",
+ "Password update failed"
);
}
@@ -130,5 +149,5 @@ export const resetPasswordAction = async (formData: FormData) => {
export const signOutAction = async () => {
const supabase = await createClient();
await supabase.auth.signOut();
- return redirect("/sign-in");
+ return redirect("/login");
};
diff --git a/app/auth/callback/route.ts b/app/auth/callback/route.ts
index dd415a4..384d5b8 100644
--- a/app/auth/callback/route.ts
+++ b/app/auth/callback/route.ts
@@ -14,11 +14,11 @@ export async function GET(request: Request) {
const supabase = await createClient();
await supabase.auth.exchangeCodeForSession(code);
}
-
+ console.log("code", code);
if (redirectTo) {
return NextResponse.redirect(`${origin}${redirectTo}`);
}
// URL to redirect to after sign up process completes
- return NextResponse.redirect(`${origin}/protected`);
+ return NextResponse.redirect(`${origin}/dashboard`);
}
diff --git a/app/dashboard/upload/page.tsx b/app/dashboard/upload/page.tsx
new file mode 100644
index 0000000..2d02584
--- /dev/null
+++ b/app/dashboard/upload/page.tsx
@@ -0,0 +1,57 @@
+import UploadZone from "@/components/UploadZone";
+import { AppSidebar } from "@/components/app-sidebar";
+import { NavActions } from "@/components/nav-actions";
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbList,
+ BreadcrumbPage,
+} from "@/components/ui/breadcrumb";
+import { Separator } from "@/components/ui/separator";
+import {
+ SidebarInset,
+ SidebarProvider,
+ SidebarTrigger,
+} from "@/components/ui/sidebar";
+import { createClient } from "@/utils/supabase/server";
+import { CloudUpload } from "lucide-react";
+import { redirect } from "next/navigation";
+
+export default async function Page() {
+ const supabase = await createClient();
+
+ const {
+ data: { user },
+ } = await supabase.auth.getUser();
+
+ if (!user) {
+ return redirect("/login");
+ }
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/dashboard/upload/process/route.ts b/app/dashboard/upload/process/route.ts
new file mode 100644
index 0000000..425f284
--- /dev/null
+++ b/app/dashboard/upload/process/route.ts
@@ -0,0 +1,47 @@
+import { createClient } from "@/utils/supabase/server";
+import { NextResponse } from "next/server";
+import { Mistral } from "@mistralai/mistralai";
+
+const apiKey = process.env.MISTRAL_API_KEY;
+const client = new Mistral({ apiKey: apiKey });
+
+export async function POST(request: Request) {
+ const supabase = await createClient();
+ const formData = await request.formData();
+ const file = formData.get("file") as File;
+ const fileName = formData.get("fileName") as string;
+ const id = formData.get("id") as string;
+
+ const uploaded_pdf = await client.files.upload({
+ file: {
+ fileName,
+ content: file,
+ },
+ purpose: "ocr",
+ });
+
+ const signedUrl = await client.files.getSignedUrl({
+ fileId: uploaded_pdf.id,
+ });
+
+ const ocrResponse = await client.ocr.process({
+ model: "mistral-ocr-latest",
+ document: {
+ type: "document_url",
+ documentUrl: signedUrl.url,
+ },
+ });
+
+ const { data, error } = await supabase
+ .from("documents")
+ .update({
+ ocr_data: ocrResponse,
+ })
+ .eq("id", id);
+ if (error) {
+ console.error(error);
+ return NextResponse.json({ error: error.message }, { status: 500 });
+ }
+ console.log("Document updated successfully:", data);
+ return NextResponse.json({ message: "File processed successfully" });
+}
diff --git a/app/login/page.tsx b/app/login/page.tsx
index 94b501b..032da59 100644
--- a/app/login/page.tsx
+++ b/app/login/page.tsx
@@ -1,8 +1,15 @@
import { Brain, BrainCircuit, GalleryVerticalEnd } from "lucide-react";
import { LoginForm } from "@/components/login-form";
+import { FormMessage } from "@/components/form-message";
+
+export default async function LoginPage(props: {
+ searchParams: Promise<
+ { success: string } | { error: string } | { message: string }
+ >;
+}) {
+ const searchParams = await props.searchParams;
-export default function LoginPage() {
return (
@@ -12,6 +19,7 @@ export default function LoginPage() {
Neuroread
+
diff --git a/bun.lockb b/bun.lockb
index 36eaec4..dffef7b 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/components/UploadZone.tsx b/components/UploadZone.tsx
new file mode 100644
index 0000000..4e50314
--- /dev/null
+++ b/components/UploadZone.tsx
@@ -0,0 +1,83 @@
+"use client";
+import { createClient } from "@/utils/supabase/client";
+import { CloudUpload } from "lucide-react";
+
+export default async function UploadZone() {
+ const supabase = await createClient();
+
+ const {
+ data: { user },
+ } = await supabase.auth.getUser();
+
+ const onUpload = async (file: File) => {
+ const uuid = crypto.randomUUID();
+
+ const { data: fileData, error: fileError } = await supabase.storage
+ .from("documents")
+ .upload(`public/${uuid}.pdf`, file);
+
+ if (fileError) {
+ console.error(fileError);
+ return;
+ }
+
+ console.log("File uploaded successfully:", fileData);
+
+ const { data, error } = await supabase.from("documents").insert({
+ id: uuid,
+ file_name: file.name,
+ owner: user!.id,
+ raw_file: fileData.id,
+ });
+
+ if (error) {
+ console.error(error);
+ return;
+ }
+
+ console.log("Document inserted successfully:", data);
+
+ // process file at /dashboard/upload/process
+ const formData = new FormData();
+ formData.append("file", file);
+ formData.append("fileName", file.name);
+ formData.append("id", uuid);
+ const response = await fetch("/dashboard/upload/process", {
+ method: "POST",
+ body: formData,
+ });
+ const result = await response.json();
+ console.log("File processed successfully:", result);
+ };
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/components/app-sidebar.tsx b/components/app-sidebar.tsx
index 741a40b..16c1ecf 100644
--- a/components/app-sidebar.tsx
+++ b/components/app-sidebar.tsx
@@ -1,9 +1,10 @@
-"use client"
+"use client";
-import * as React from "react"
+import * as React from "react";
import {
AudioWaveform,
Blocks,
+ BrainCircuit,
Calendar,
Command,
Home,
@@ -13,264 +14,126 @@ import {
Settings2,
Sparkles,
Trash2,
-} from "lucide-react"
+ Upload,
+} from "lucide-react";
-import { NavFavorites } from "@/components/nav-favorites"
-import { NavMain } from "@/components/nav-main"
-import { NavSecondary } from "@/components/nav-secondary"
-import { NavWorkspaces } from "@/components/nav-workspaces"
-import { TeamSwitcher } from "@/components/team-switcher"
+import { NavDocuments } from "@/components/nav-favorites";
+import { NavMain } from "@/components/nav-main";
+import { NavSecondary } from "@/components/nav-secondary";
import {
Sidebar,
SidebarContent,
SidebarHeader,
+ SidebarMenuButton,
SidebarRail,
-} from "@/components/ui/sidebar"
-
-// This is sample data.
-const data = {
- teams: [
- {
- name: "Acme Inc",
- logo: Command,
- plan: "Enterprise",
- },
- {
- name: "Acme Corp.",
- logo: AudioWaveform,
- plan: "Startup",
- },
- {
- name: "Evil Corp.",
- logo: Command,
- plan: "Free",
- },
- ],
- navMain: [
- {
- title: "Search",
- url: "#",
- icon: Search,
- },
- {
- title: "Ask AI",
- url: "#",
- icon: Sparkles,
- },
- {
- title: "Home",
- url: "#",
- icon: Home,
- isActive: true,
- },
- {
- title: "Inbox",
- url: "#",
- icon: Inbox,
- badge: "10",
- },
- ],
- navSecondary: [
- {
- title: "Calendar",
- url: "#",
- icon: Calendar,
- },
- {
- title: "Settings",
- url: "#",
- icon: Settings2,
- },
- {
- title: "Templates",
- url: "#",
- icon: Blocks,
- },
- {
- title: "Trash",
- url: "#",
- icon: Trash2,
- },
- {
- title: "Help",
- url: "#",
- icon: MessageCircleQuestion,
- },
- ],
- favorites: [
- {
- name: "Project Management & Task Tracking",
- url: "#",
- emoji: "π",
- },
- {
- name: "Family Recipe Collection & Meal Planning",
- url: "#",
- emoji: "π³",
- },
- {
- name: "Fitness Tracker & Workout Routines",
- url: "#",
- emoji: "πͺ",
- },
- {
- name: "Book Notes & Reading List",
- url: "#",
- emoji: "π",
- },
- {
- name: "Sustainable Gardening Tips & Plant Care",
- url: "#",
- emoji: "π±",
- },
- {
- name: "Language Learning Progress & Resources",
- url: "#",
- emoji: "π£οΈ",
- },
- {
- name: "Home Renovation Ideas & Budget Tracker",
- url: "#",
- emoji: "π ",
- },
- {
- name: "Personal Finance & Investment Portfolio",
- url: "#",
- emoji: "π°",
- },
- {
- name: "Movie & TV Show Watchlist with Reviews",
- url: "#",
- emoji: "π¬",
- },
- {
- name: "Daily Habit Tracker & Goal Setting",
- url: "#",
- emoji: "β
",
- },
- ],
- workspaces: [
- {
- name: "Personal Life Management",
- emoji: "π ",
- pages: [
- {
- name: "Daily Journal & Reflection",
- url: "#",
- emoji: "π",
- },
- {
- name: "Health & Wellness Tracker",
- url: "#",
- emoji: "π",
- },
- {
- name: "Personal Growth & Learning Goals",
- url: "#",
- emoji: "π",
- },
- ],
- },
- {
- name: "Professional Development",
- emoji: "πΌ",
- pages: [
- {
- name: "Career Objectives & Milestones",
- url: "#",
- emoji: "π―",
- },
- {
- name: "Skill Acquisition & Training Log",
- url: "#",
- emoji: "π§ ",
- },
- {
- name: "Networking Contacts & Events",
- url: "#",
- emoji: "π€",
- },
- ],
- },
- {
- name: "Creative Projects",
- emoji: "π¨",
- pages: [
- {
- name: "Writing Ideas & Story Outlines",
- url: "#",
- emoji: "βοΈ",
- },
- {
- name: "Art & Design Portfolio",
- url: "#",
- emoji: "πΌοΈ",
- },
- {
- name: "Music Composition & Practice Log",
- url: "#",
- emoji: "π΅",
- },
- ],
- },
- {
- name: "Home Management",
- emoji: "π‘",
- pages: [
- {
- name: "Household Budget & Expense Tracking",
- url: "#",
- emoji: "π°",
- },
- {
- name: "Home Maintenance Schedule & Tasks",
- url: "#",
- emoji: "π§",
- },
- {
- name: "Family Calendar & Event Planning",
- url: "#",
- emoji: "π
",
- },
- ],
- },
- {
- name: "Travel & Adventure",
- emoji: "π§³",
- pages: [
- {
- name: "Trip Planning & Itineraries",
- url: "#",
- emoji: "πΊοΈ",
- },
- {
- name: "Travel Bucket List & Inspiration",
- url: "#",
- emoji: "π",
- },
- {
- name: "Travel Journal & Photo Gallery",
- url: "#",
- emoji: "πΈ",
- },
- ],
- },
- ],
-}
+} from "@/components/ui/sidebar";
export function AppSidebar({ ...props }: React.ComponentProps) {
+ const data = {
+ navMain: [
+ {
+ title: "Search",
+ url: "/dashboard/search",
+ icon: Search,
+ },
+ {
+ title: "Home",
+ url: "/dashboard",
+ icon: Home,
+ isActive: true,
+ },
+ {
+ title: "Upload",
+ url: "/dashboard/upload",
+ icon: Upload,
+ },
+ ],
+ navSecondary: [
+ {
+ title: "Settings",
+ url: "#",
+ icon: Settings2,
+ },
+ {
+ title: "Trash",
+ url: "#",
+ icon: Trash2,
+ },
+ {
+ title: "Help",
+ url: "#",
+ icon: MessageCircleQuestion,
+ },
+ ],
+ favorites: [
+ {
+ name: "Project Management & Task Tracking",
+ url: "#",
+ emoji: "π",
+ },
+ {
+ name: "Family Recipe Collection & Meal Planning",
+ url: "#",
+ emoji: "π³",
+ },
+ {
+ name: "Fitness Tracker & Workout Routines",
+ url: "#",
+ emoji: "πͺ",
+ },
+ {
+ name: "Book Notes & Reading List",
+ url: "#",
+ emoji: "π",
+ },
+ {
+ name: "Sustainable Gardening Tips & Plant Care",
+ url: "#",
+ emoji: "π±",
+ },
+ {
+ name: "Language Learning Progress & Resources",
+ url: "#",
+ emoji: "π£οΈ",
+ },
+ {
+ name: "Home Renovation Ideas & Budget Tracker",
+ url: "#",
+ emoji: "π ",
+ },
+ {
+ name: "Personal Finance & Investment Portfolio",
+ url: "#",
+ emoji: "π°",
+ },
+ {
+ name: "Movie & TV Show Watchlist with Reviews",
+ url: "#",
+ emoji: "π¬",
+ },
+ {
+ name: "Daily Habit Tracker & Goal Setting",
+ url: "#",
+ emoji: "β
",
+ },
+ ],
+ };
return (
-
+
+
+
+
+ Neuroread
+
-
-
+
- )
+ );
}
diff --git a/components/login-form.tsx b/components/login-form.tsx
index 44add0e..31b8b02 100644
--- a/components/login-form.tsx
+++ b/components/login-form.tsx
@@ -9,6 +9,8 @@ import {
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
+import { createClient } from "@/utils/supabase/client";
+import { signInAction } from "@/app/actions";
export function LoginForm({
className,
@@ -22,44 +24,51 @@ export function LoginForm({
Login with your Google account
-
diff --git a/components/nav-favorites.tsx b/components/nav-favorites.tsx
index 34e2aea..cb3382e 100644
--- a/components/nav-favorites.tsx
+++ b/components/nav-favorites.tsx
@@ -1,12 +1,13 @@
-"use client"
+"use client";
import {
ArrowUpRight,
+ FileText,
Link,
MoreHorizontal,
StarOff,
Trash2,
-} from "lucide-react"
+} from "lucide-react";
import {
DropdownMenu,
@@ -14,7 +15,7 @@ import {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu"
+} from "@/components/ui/dropdown-menu";
import {
SidebarGroup,
SidebarGroupLabel,
@@ -23,28 +24,28 @@ import {
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
-} from "@/components/ui/sidebar"
+} from "@/components/ui/sidebar";
-export function NavFavorites({
- favorites,
+export function NavDocuments({
+ documents,
}: {
- favorites: {
- name: string
- url: string
- emoji: string
- }[]
+ documents: {
+ name: string;
+ url: string;
+ emoji?: string;
+ }[];
}) {
- const { isMobile } = useSidebar()
+ const { isMobile } = useSidebar();
return (
- Favorites
+ Documents
- {favorites.map((item) => (
+ {documents.map((item) => (
- {item.emoji}
+ {item.emoji ? item.emoji : }
{item.name}
@@ -90,5 +91,5 @@ export function NavFavorites({
- )
+ );
}
diff --git a/components/nav-main.tsx b/components/nav-main.tsx
index 31edc97..0460b1e 100644
--- a/components/nav-main.tsx
+++ b/components/nav-main.tsx
@@ -1,28 +1,30 @@
-"use client"
+"use client";
-import { type LucideIcon } from "lucide-react"
+import { type LucideIcon } from "lucide-react";
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
-} from "@/components/ui/sidebar"
+} from "@/components/ui/sidebar";
+import { usePathname, useRouter } from "next/navigation";
export function NavMain({
items,
}: {
items: {
- title: string
- url: string
- icon: LucideIcon
- isActive?: boolean
- }[]
+ title: string;
+ url: string;
+ icon: LucideIcon;
+ isActive?: boolean;
+ }[];
}) {
+ const pathname = usePathname();
return (
{items.map((item) => (
-
+
{item.title}
@@ -31,5 +33,5 @@ export function NavMain({
))}
- )
+ );
}
diff --git a/components/ui/sidebar.tsx b/components/ui/sidebar.tsx
index 3b3ee77..485ac82 100644
--- a/components/ui/sidebar.tsx
+++ b/components/ui/sidebar.tsx
@@ -1,56 +1,56 @@
-"use client"
+"use client";
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { VariantProps, cva } from "class-variance-authority"
-import { PanelLeftIcon } from "lucide-react"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { VariantProps, cva } from "class-variance-authority";
+import { PanelLeftIcon } from "lucide-react";
-import { useIsMobile } from "@/components/hooks/use-mobile"
-import { cn } from "@/components/lib/utils"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Separator } from "@/components/ui/separator"
+import { useIsMobile } from "@/hooks/use-mobile";
+import { cn } from "@/lib/utils";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Separator } from "@/components/ui/separator";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
-} from "@/components/ui/sheet"
-import { Skeleton } from "@/components/ui/skeleton"
+} from "@/components/ui/sheet";
+import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
-} from "@/components/ui/tooltip"
+} from "@/components/ui/tooltip";
-const SIDEBAR_COOKIE_NAME = "sidebar_state"
-const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
-const SIDEBAR_WIDTH = "16rem"
-const SIDEBAR_WIDTH_MOBILE = "18rem"
-const SIDEBAR_WIDTH_ICON = "3rem"
-const SIDEBAR_KEYBOARD_SHORTCUT = "b"
+const SIDEBAR_COOKIE_NAME = "sidebar_state";
+const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
+const SIDEBAR_WIDTH = "16rem";
+const SIDEBAR_WIDTH_MOBILE = "18rem";
+const SIDEBAR_WIDTH_ICON = "3rem";
+const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContextProps = {
- state: "expanded" | "collapsed"
- open: boolean
- setOpen: (open: boolean) => void
- openMobile: boolean
- setOpenMobile: (open: boolean) => void
- isMobile: boolean
- toggleSidebar: () => void
-}
+ state: "expanded" | "collapsed";
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ openMobile: boolean;
+ setOpenMobile: (open: boolean) => void;
+ isMobile: boolean;
+ toggleSidebar: () => void;
+};
-const SidebarContext = React.createContext(null)
+const SidebarContext = React.createContext(null);
function useSidebar() {
- const context = React.useContext(SidebarContext)
+ const context = React.useContext(SidebarContext);
if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.")
+ throw new Error("useSidebar must be used within a SidebarProvider.");
}
- return context
+ return context;
}
function SidebarProvider({
@@ -62,36 +62,36 @@ function SidebarProvider({
children,
...props
}: React.ComponentProps<"div"> & {
- defaultOpen?: boolean
- open?: boolean
- onOpenChange?: (open: boolean) => void
+ defaultOpen?: boolean;
+ open?: boolean;
+ onOpenChange?: (open: boolean) => void;
}) {
- const isMobile = useIsMobile()
- const [openMobile, setOpenMobile] = React.useState(false)
+ const isMobile = useIsMobile();
+ const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen)
- const open = openProp ?? _open
+ const [_open, _setOpen] = React.useState(defaultOpen);
+ const open = openProp ?? _open;
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value
+ const openState = typeof value === "function" ? value(open) : value;
if (setOpenProp) {
- setOpenProp(openState)
+ setOpenProp(openState);
} else {
- _setOpen(openState)
+ _setOpen(openState);
}
// This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
[setOpenProp, open]
- )
+ );
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
- }, [isMobile, setOpen, setOpenMobile])
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
+ }, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
@@ -100,18 +100,18 @@ function SidebarProvider({
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
(event.metaKey || event.ctrlKey)
) {
- event.preventDefault()
- toggleSidebar()
+ event.preventDefault();
+ toggleSidebar();
}
- }
+ };
- window.addEventListener("keydown", handleKeyDown)
- return () => window.removeEventListener("keydown", handleKeyDown)
- }, [toggleSidebar])
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [toggleSidebar]);
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed"
+ const state = open ? "expanded" : "collapsed";
const contextValue = React.useMemo(
() => ({
@@ -124,7 +124,7 @@ function SidebarProvider({
toggleSidebar,
}),
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- )
+ );
return (
@@ -148,7 +148,7 @@ function SidebarProvider({
- )
+ );
}
function Sidebar({
@@ -159,11 +159,11 @@ function Sidebar({
children,
...props
}: React.ComponentProps<"div"> & {
- side?: "left" | "right"
- variant?: "sidebar" | "floating" | "inset"
- collapsible?: "offcanvas" | "icon" | "none"
+ side?: "left" | "right";
+ variant?: "sidebar" | "floating" | "inset";
+ collapsible?: "offcanvas" | "icon" | "none";
}) {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
if (collapsible === "none") {
return (
@@ -177,7 +177,7 @@ function Sidebar({
>
{children}
- )
+ );
}
if (isMobile) {
@@ -202,7 +202,7 @@ function Sidebar({
{children}
- )
+ );
}
return (
@@ -250,7 +250,7 @@ function Sidebar({
- )
+ );
}
function SidebarTrigger({
@@ -258,7 +258,7 @@ function SidebarTrigger({
onClick,
...props
}: React.ComponentProps) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (
- )
+ );
}
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (