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 ( + + + +
+
+ + + + + + + Upload a Document + + + + +
+
+ +
+
+ ); +} 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 -
-
-
- -
-
- - Or continue with - -
-
-
- - + + +
- -
+ + Continue with Google + + +
+ + Or continue with +
- +
+
+ + +
+ +
+
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 (