diff options
Diffstat (limited to 'apps/web')
73 files changed, 319 insertions, 299 deletions
diff --git a/apps/web/app/api/trpc/[trpc]/route.ts b/apps/web/app/api/trpc/[trpc]/route.ts index 02ca966d..23df286f 100644 --- a/apps/web/app/api/trpc/[trpc]/route.ts +++ b/apps/web/app/api/trpc/[trpc]/route.ts @@ -1,8 +1,9 @@ -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { appRouter } from "@hoarder/trpc/routers/_app"; import { createContext } from "@/server/api/client"; -import { authenticateApiKey } from "@hoarder/trpc/auth"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; + import { db } from "@hoarder/db"; +import { authenticateApiKey } from "@hoarder/trpc/auth"; +import { appRouter } from "@hoarder/trpc/routers/_app"; const handler = (req: Request) => fetchRequestHandler({ @@ -21,7 +22,7 @@ const handler = (req: Request) => // Check if the request has an Authorization token, if it does, assume that API key authentication is requested. const authorizationHeader = opts.req.headers.get("Authorization"); if (authorizationHeader && authorizationHeader.startsWith("Bearer ")) { - const token = authorizationHeader.split(" ")[1]!; + const token = authorizationHeader.split(" ")[1]; try { const user = await authenticateApiKey(token); return { user, db }; diff --git a/apps/web/app/dashboard/admin/page.tsx b/apps/web/app/dashboard/admin/page.tsx index 6babdd79..7b4c3cdd 100644 --- a/apps/web/app/dashboard/admin/page.tsx +++ b/apps/web/app/dashboard/admin/page.tsx @@ -1,5 +1,6 @@ "use client"; +import { useRouter } from "next/navigation"; import { ActionButton } from "@/components/ui/action-button"; import LoadingSpinner from "@/components/ui/spinner"; import { @@ -15,7 +16,6 @@ import { api } from "@/lib/trpc"; import { keepPreviousData } from "@tanstack/react-query"; import { Trash } from "lucide-react"; import { useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; function ActionsSection() { const { mutate: recrawlLinks, isPending: isRecrawlPending } = diff --git a/apps/web/app/dashboard/bookmarks/layout.tsx b/apps/web/app/dashboard/bookmarks/layout.tsx index 71ee143b..ca99a87b 100644 --- a/apps/web/app/dashboard/bookmarks/layout.tsx +++ b/apps/web/app/dashboard/bookmarks/layout.tsx @@ -1,6 +1,6 @@ +import type { Metadata } from "next"; import React from "react"; import TopNav from "@/components/dashboard/bookmarks/TopNav"; -import type { Metadata } from "next"; export const metadata: Metadata = { title: "Hoarder - Bookmarks", diff --git a/apps/web/app/dashboard/layout.tsx b/apps/web/app/dashboard/layout.tsx index 31d592fb..dc3af9c7 100644 --- a/apps/web/app/dashboard/layout.tsx +++ b/apps/web/app/dashboard/layout.tsx @@ -1,6 +1,6 @@ -import { Separator } from "@/components/ui/separator"; import MobileSidebar from "@/components/dashboard/sidebar/ModileSidebar"; import Sidebar from "@/components/dashboard/sidebar/Sidebar"; +import { Separator } from "@/components/ui/separator"; export default async function Dashboard({ children, diff --git a/apps/web/app/dashboard/lists/[listId]/page.tsx b/apps/web/app/dashboard/lists/[listId]/page.tsx index 006fd3ad..4e35c377 100644 --- a/apps/web/app/dashboard/lists/[listId]/page.tsx +++ b/apps/web/app/dashboard/lists/[listId]/page.tsx @@ -1,9 +1,9 @@ +import { notFound, redirect } from "next/navigation"; +import DeleteListButton from "@/components/dashboard/lists/DeleteListButton"; +import ListView from "@/components/dashboard/lists/ListView"; import { api } from "@/server/api/client"; import { getServerAuthSession } from "@/server/auth"; import { TRPCError } from "@trpc/server"; -import { notFound, redirect } from "next/navigation"; -import ListView from "@/components/dashboard/lists/ListView"; -import DeleteListButton from "@/components/dashboard/lists/DeleteListButton"; export default async function ListPage({ params, diff --git a/apps/web/app/dashboard/lists/page.tsx b/apps/web/app/dashboard/lists/page.tsx index 88eeda47..a8c53eb6 100644 --- a/apps/web/app/dashboard/lists/page.tsx +++ b/apps/web/app/dashboard/lists/page.tsx @@ -1,5 +1,5 @@ -import { api } from "@/server/api/client"; import AllListsView from "@/components/dashboard/lists/AllListsView"; +import { api } from "@/server/api/client"; export default async function ListsPage() { const lists = await api.lists.list(); diff --git a/apps/web/app/dashboard/preview/[bookmarkId]/page.tsx b/apps/web/app/dashboard/preview/[bookmarkId]/page.tsx index 707d2b69..5f10b56e 100644 --- a/apps/web/app/dashboard/preview/[bookmarkId]/page.tsx +++ b/apps/web/app/dashboard/preview/[bookmarkId]/page.tsx @@ -1,5 +1,5 @@ -import { api } from "@/server/api/client"; import BookmarkPreview from "@/components/dashboard/bookmarks/BookmarkPreview"; +import { api } from "@/server/api/client"; export default async function BookmarkPreviewPage({ params, diff --git a/apps/web/app/dashboard/search/page.tsx b/apps/web/app/dashboard/search/page.tsx index 602f6aa0..38099c18 100644 --- a/apps/web/app/dashboard/search/page.tsx +++ b/apps/web/app/dashboard/search/page.tsx @@ -1,11 +1,12 @@ "use client"; -import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; -import Loading from "../bookmarks/loading"; import { Suspense, useRef } from "react"; +import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; import { SearchInput } from "@/components/dashboard/search/SearchInput"; import { useBookmarkSearch } from "@/lib/hooks/bookmark-search"; +import Loading from "../bookmarks/loading"; + function SearchComp() { const { data, isPending, isPlaceholderData } = useBookmarkSearch(); diff --git a/apps/web/app/dashboard/settings/page.tsx b/apps/web/app/dashboard/settings/page.tsx index 38091e6c..3d54d2d7 100644 --- a/apps/web/app/dashboard/settings/page.tsx +++ b/apps/web/app/dashboard/settings/page.tsx @@ -1,4 +1,5 @@ import ApiKeySettings from "@/components/dashboard/settings/ApiKeySettings"; + export default async function Settings() { return ( <div className="m-4 flex flex-col space-y-2 rounded-md border bg-white p-4"> diff --git a/apps/web/app/dashboard/tags/[tagName]/page.tsx b/apps/web/app/dashboard/tags/[tagName]/page.tsx index c978b86a..51b3cb0b 100644 --- a/apps/web/app/dashboard/tags/[tagName]/page.tsx +++ b/apps/web/app/dashboard/tags/[tagName]/page.tsx @@ -1,11 +1,12 @@ -import { getServerAuthSession } from "@/server/auth"; -import { db } from "@hoarder/db"; import { notFound, redirect } from "next/navigation"; import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; import { api } from "@/server/api/client"; -import { bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema"; +import { getServerAuthSession } from "@/server/auth"; import { and, eq } from "drizzle-orm"; +import { db } from "@hoarder/db"; +import { bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema"; + export default async function TagPage({ params, }: { diff --git a/apps/web/app/dashboard/tags/page.tsx b/apps/web/app/dashboard/tags/page.tsx index 44c164e1..08acd968 100644 --- a/apps/web/app/dashboard/tags/page.tsx +++ b/apps/web/app/dashboard/tags/page.tsx @@ -1,15 +1,16 @@ +import Link from "next/link"; +import { redirect } from "next/navigation"; import { Separator } from "@/components/ui/separator"; import { getServerAuthSession } from "@/server/auth"; +import { count, eq } from "drizzle-orm"; + import { db } from "@hoarder/db"; import { bookmarkTags, tagsOnBookmarks } from "@hoarder/db/schema"; -import { count, eq } from "drizzle-orm"; -import Link from "next/link"; -import { redirect } from "next/navigation"; function TagPill({ name, count }: { name: string; count: number }) { return ( <Link - className="text-foreground hover:bg-foreground hover:text-background flex gap-2 rounded-md border border-gray-200 bg-white px-2 py-1" + className="flex gap-2 rounded-md border border-gray-200 bg-white px-2 py-1 text-foreground hover:bg-foreground hover:text-background" href={`/dashboard/tags/${name}`} > {name} <Separator orientation="vertical" /> {count} diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index b1790a1f..6ec9c3e4 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,12 +1,14 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; + import "./globals.css"; + +import type { Viewport } from "next"; import React from "react"; import { Toaster } from "@/components/ui/toaster"; import Providers from "@/lib/providers"; -import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { getServerAuthSession } from "@/server/auth"; -import type { Viewport } from "next"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; const inter = Inter({ subsets: ["latin"] }); diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index f467b64b..ca076cbf 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,5 +1,5 @@ -import { getServerAuthSession } from "@/server/auth"; import { redirect } from "next/navigation"; +import { getServerAuthSession } from "@/server/auth"; export default async function Home() { // TODO: Home currently just redirects between pages until we build a proper landing page diff --git a/apps/web/app/signin/page.tsx b/apps/web/app/signin/page.tsx index fed71b62..4dc81376 100644 --- a/apps/web/app/signin/page.tsx +++ b/apps/web/app/signin/page.tsx @@ -1,7 +1,7 @@ -import { PackageOpen } from "lucide-react"; -import SignInForm from "@/components/signin/SignInForm"; import { redirect } from "next/dist/client/components/navigation"; +import SignInForm from "@/components/signin/SignInForm"; import { getServerAuthSession } from "@/server/auth"; +import { PackageOpen } from "lucide-react"; export default async function SignInPage() { const session = await getServerAuthSession(); diff --git a/apps/web/components/dashboard/bookmarks/AddLinkButton.tsx b/apps/web/components/dashboard/bookmarks/AddLinkButton.tsx index 5973f909..45a67020 100644 --- a/apps/web/components/dashboard/bookmarks/AddLinkButton.tsx +++ b/apps/web/components/dashboard/bookmarks/AddLinkButton.tsx @@ -1,10 +1,5 @@ -import { Form, FormControl, FormField, FormItem } from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; -import { useForm, SubmitErrorHandler } from "react-hook-form"; -import { z } from "zod"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { toast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; +import type { SubmitErrorHandler } from "react-hook-form"; +import { useState } from "react"; import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { @@ -16,7 +11,13 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { useState } from "react"; +import { Form, FormControl, FormField, FormItem } from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; export function AddLinkButton({ children }: { children: React.ReactNode }) { const [isOpen, setOpen] = useState(false); diff --git a/apps/web/components/dashboard/bookmarks/AddToListModal.tsx b/apps/web/components/dashboard/bookmarks/AddToListModal.tsx index c9fd5da0..6242aa27 100644 --- a/apps/web/components/dashboard/bookmarks/AddToListModal.tsx +++ b/apps/web/components/dashboard/bookmarks/AddToListModal.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { @@ -15,11 +16,6 @@ import { FormItem, FormMessage, } from "@/components/ui/form"; - -import { toast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { useState } from "react"; - import { Select, SelectContent, @@ -29,9 +25,11 @@ import { SelectValue, } from "@/components/ui/select"; import LoadingSpinner from "@/components/ui/spinner"; -import { z } from "zod"; -import { useForm } from "react-hook-form"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; export default function AddToListModal({ bookmarkId, @@ -115,12 +113,11 @@ export default function AddToListModal({ </SelectTrigger> <SelectContent> <SelectGroup> - {lists && - lists.lists.map((l) => ( - <SelectItem key={l.id} value={l.id}> - {l.icon} {l.name} - </SelectItem> - ))} + {lists?.lists.map((l) => ( + <SelectItem key={l.id} value={l.id}> + {l.icon} {l.name} + </SelectItem> + ))} </SelectGroup> </SelectContent> </Select> diff --git a/apps/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx b/apps/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx index 1f5fa433..026b8d37 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkCardSkeleton.tsx @@ -1,10 +1,10 @@ import { ImageCard, + ImageCardBanner, ImageCardBody, ImageCardContent, ImageCardFooter, ImageCardTitle, - ImageCardBanner, } from "@/components/ui/imageCard"; import { Skeleton } from "@/components/ui/skeleton"; diff --git a/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx b/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx index 4f08ebee..3656a435 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkOptions.tsx @@ -1,8 +1,6 @@ "use client"; -import { useToast } from "@/components/ui/use-toast"; -import { api } from "@/lib/trpc"; -import { ZBookmark, ZBookmarkedLink } from "@hoarder/trpc/types/bookmarks"; +import { useState } from "react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -10,6 +8,8 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; +import { useToast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; import { Archive, Link, @@ -21,10 +21,12 @@ import { Tags, Trash2, } from "lucide-react"; -import { useTagModel } from "./TagModal"; -import { useState } from "react"; -import { BookmarkedTextEditor } from "./BookmarkedTextEditor"; + +import type { ZBookmark, ZBookmarkedLink } from "@hoarder/trpc/types/bookmarks"; + import { useAddToListModal } from "./AddToListModal"; +import { BookmarkedTextEditor } from "./BookmarkedTextEditor"; +import { useTagModel } from "./TagModal"; export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) { const { toast } = useToast(); diff --git a/apps/web/components/dashboard/bookmarks/BookmarkPreview.tsx b/apps/web/components/dashboard/bookmarks/BookmarkPreview.tsx index 2a8ae1b1..69aa60a3 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkPreview.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkPreview.tsx @@ -1,14 +1,15 @@ "use client"; +import Link from "next/link"; import { BackButton } from "@/components/ui/back-button"; import { Skeleton } from "@/components/ui/skeleton"; import { isBookmarkStillCrawling } from "@/lib/bookmarkUtils"; import { api } from "@/lib/trpc"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; import { ArrowLeftCircle, CalendarDays, ExternalLink } from "lucide-react"; -import Link from "next/link"; import Markdown from "react-markdown"; +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; + export default function BookmarkPreview({ initialData, }: { @@ -37,7 +38,7 @@ export default function BookmarkPreview({ const linkHeader = bookmark.content.type == "link" && ( <div className="flex flex-col space-y-2"> <p className="text-center text-3xl"> - {bookmark.content.title || bookmark.content.url} + {bookmark.content.title ?? bookmark.content.url} </p> <Link href={bookmark.content.url} className="mx-auto flex gap-2"> <span className="my-auto">View Original</span> @@ -72,7 +73,7 @@ export default function BookmarkPreview({ } return ( - <div className="bg-background m-4 min-h-screen space-y-4 rounded-md border p-4"> + <div className="m-4 min-h-screen space-y-4 rounded-md border bg-background p-4"> <div className="flex justify-between"> <BackButton className="ghost" variant="ghost"> <ArrowLeftCircle /> diff --git a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx index a5b58f1a..eb618474 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx @@ -1,4 +1,6 @@ -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; +import { useState } from "react"; +import { ActionButton } from "@/components/ui/action-button"; +import { Button } from "@/components/ui/button"; import { Dialog, DialogClose, @@ -8,12 +10,11 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { ActionButton } from "@/components/ui/action-button"; -import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; -import { api } from "@/lib/trpc"; -import { useState } from "react"; import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; + +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; export function BookmarkedTextEditor({ bookmark, diff --git a/apps/web/components/dashboard/bookmarks/Bookmarks.tsx b/apps/web/components/dashboard/bookmarks/Bookmarks.tsx index 1ad3670c..9f001551 100644 --- a/apps/web/components/dashboard/bookmarks/Bookmarks.tsx +++ b/apps/web/components/dashboard/bookmarks/Bookmarks.tsx @@ -1,9 +1,11 @@ import { redirect } from "next/navigation"; -import BookmarksGrid from "./BookmarksGrid"; -import { ZGetBookmarksRequest } from "@hoarder/trpc/types/bookmarks"; import { api } from "@/server/api/client"; import { getServerAuthSession } from "@/server/auth"; +import type { ZGetBookmarksRequest } from "@hoarder/trpc/types/bookmarks"; + +import BookmarksGrid from "./BookmarksGrid"; + export default async function Bookmarks({ favourited, archived, diff --git a/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx b/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx index 4d5b6b0a..dd529a8b 100644 --- a/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx +++ b/apps/web/components/dashboard/bookmarks/BookmarksGrid.tsx @@ -1,14 +1,19 @@ "use client"; -import LinkCard from "./LinkCard"; -import { ZBookmark, ZGetBookmarksRequest } from "@hoarder/trpc/types/bookmarks"; +import { useMemo } from "react"; import { api } from "@/lib/trpc"; -import TextCard from "./TextCard"; +import tailwindConfig from "@/tailwind.config"; import { Slot } from "@radix-ui/react-slot"; import Masonry from "react-masonry-css"; import resolveConfig from "tailwindcss/resolveConfig"; -import tailwindConfig from "@/tailwind.config"; -import { useMemo } from "react"; + +import type { + ZBookmark, + ZGetBookmarksRequest, +} from "@hoarder/trpc/types/bookmarks"; + +import LinkCard from "./LinkCard"; +import TextCard from "./TextCard"; function getBreakpointConfig() { const fullConfig = resolveConfig(tailwindConfig); diff --git a/apps/web/components/dashboard/bookmarks/LinkCard.tsx b/apps/web/components/dashboard/bookmarks/LinkCard.tsx index 50f30e47..808e6d91 100644 --- a/apps/web/components/dashboard/bookmarks/LinkCard.tsx +++ b/apps/web/components/dashboard/bookmarks/LinkCard.tsx @@ -1,5 +1,6 @@ "use client"; +import Link from "next/link"; import { ImageCard, ImageCardBanner, @@ -8,17 +9,18 @@ import { ImageCardFooter, ImageCardTitle, } from "@/components/ui/imageCard"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import Link from "next/link"; -import BookmarkOptions from "./BookmarkOptions"; -import { api } from "@/lib/trpc"; -import { Maximize2, Star } from "lucide-react"; -import TagList from "./TagList"; import { isBookmarkStillCrawling, isBookmarkStillLoading, isBookmarkStillTagging, } from "@/lib/bookmarkUtils"; +import { api } from "@/lib/trpc"; +import { Maximize2, Star } from "lucide-react"; + +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; + +import BookmarkOptions from "./BookmarkOptions"; +import TagList from "./TagList"; export default function LinkCard({ bookmark: initialData, diff --git a/apps/web/components/dashboard/bookmarks/TagList.tsx b/apps/web/components/dashboard/bookmarks/TagList.tsx index 6c9d2d22..cb94e5d7 100644 --- a/apps/web/components/dashboard/bookmarks/TagList.tsx +++ b/apps/web/components/dashboard/bookmarks/TagList.tsx @@ -1,9 +1,10 @@ -import { badgeVariants } from "@/components/ui/badge"; import Link from "next/link"; +import { badgeVariants } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; import { cn } from "@/lib/utils"; +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; + export default function TagList({ bookmark, loading, @@ -26,7 +27,7 @@ export default function TagList({ <Link className={cn( badgeVariants({ variant: "outline" }), - "hover:bg-foreground hover:text-secondary text-nowrap", + "text-nowrap hover:bg-foreground hover:text-secondary", )} href={`/dashboard/tags/${t.name}`} > diff --git a/apps/web/components/dashboard/bookmarks/TagModal.tsx b/apps/web/components/dashboard/bookmarks/TagModal.tsx index 8c09d00e..367e6e7d 100644 --- a/apps/web/components/dashboard/bookmarks/TagModal.tsx +++ b/apps/web/components/dashboard/bookmarks/TagModal.tsx @@ -1,3 +1,5 @@ +import type { KeyboardEvent } from "react"; +import { useEffect, useState } from "react"; import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { @@ -11,13 +13,17 @@ import { import { Input } from "@/components/ui/input"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import { ZAttachedByEnum } from "@hoarder/trpc/types/tags"; import { cn } from "@/lib/utils"; import { Sparkles, X } from "lucide-react"; -import { useState, KeyboardEvent, useEffect } from "react"; -type EditableTag = { attachedBy: ZAttachedByEnum; id?: string; name: string }; +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; +import type { ZAttachedByEnum } from "@hoarder/trpc/types/tags"; + +interface EditableTag { + attachedBy: ZAttachedByEnum; + id?: string; + name: string; +} function TagAddInput({ addTag }: { addTag: (tag: string) => void }) { const onKeyUp = (e: KeyboardEvent<HTMLInputElement>) => { diff --git a/apps/web/components/dashboard/bookmarks/TextCard.tsx b/apps/web/components/dashboard/bookmarks/TextCard.tsx index 2565e69d..5028c1bb 100644 --- a/apps/web/components/dashboard/bookmarks/TextCard.tsx +++ b/apps/web/components/dashboard/bookmarks/TextCard.tsx @@ -1,16 +1,18 @@ "use client"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import BookmarkOptions from "./BookmarkOptions"; +import { useState } from "react"; +import Link from "next/link"; +import { isBookmarkStillTagging } from "@/lib/bookmarkUtils"; import { api } from "@/lib/trpc"; -import { Maximize2, Star } from "lucide-react"; import { cn } from "@/lib/utils"; -import TagList from "./TagList"; +import { Maximize2, Star } from "lucide-react"; import Markdown from "react-markdown"; -import { useState } from "react"; + +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; + import { BookmarkedTextViewer } from "./BookmarkedTextViewer"; -import Link from "next/link"; -import { isBookmarkStillTagging } from "@/lib/bookmarkUtils"; +import BookmarkOptions from "./BookmarkOptions"; +import TagList from "./TagList"; export default function TextCard({ bookmark: initialData, diff --git a/apps/web/components/dashboard/bookmarks/TopNav.tsx b/apps/web/components/dashboard/bookmarks/TopNav.tsx index 6c0f18e5..4274762c 100644 --- a/apps/web/components/dashboard/bookmarks/TopNav.tsx +++ b/apps/web/components/dashboard/bookmarks/TopNav.tsx @@ -1,11 +1,12 @@ "use client"; -import { Link, NotebookPen } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { BookmarkedTextEditor } from "./BookmarkedTextEditor"; import { useState } from "react"; -import { AddLinkButton } from "./AddLinkButton"; +import { Button } from "@/components/ui/button"; +import { Link, NotebookPen } from "lucide-react"; + import { SearchInput } from "../search/SearchInput"; +import { AddLinkButton } from "./AddLinkButton"; +import { BookmarkedTextEditor } from "./BookmarkedTextEditor"; function AddText() { const [isEditorOpen, setEditorOpen] = useState(false); diff --git a/apps/web/components/dashboard/lists/AllListsView.tsx b/apps/web/components/dashboard/lists/AllListsView.tsx index 81f31cde..acb94edb 100644 --- a/apps/web/components/dashboard/lists/AllListsView.tsx +++ b/apps/web/components/dashboard/lists/AllListsView.tsx @@ -1,12 +1,13 @@ "use client"; +import Link from "next/link"; +import { useNewListModal } from "@/components/dashboard/sidebar/NewListModal"; import { Button } from "@/components/ui/button"; import { api } from "@/lib/trpc"; -import { ZBookmarkList } from "@hoarder/trpc/types/lists"; import { keepPreviousData } from "@tanstack/react-query"; import { Plus } from "lucide-react"; -import Link from "next/link"; -import { useNewListModal } from "@/components/dashboard/sidebar/NewListModal"; + +import type { ZBookmarkList } from "@hoarder/trpc/types/lists"; function ListItem({ name, @@ -19,7 +20,7 @@ function ListItem({ }) { return ( <Link href={path}> - <div className="bg-background rounded-md border border-gray-200 px-4 py-2 text-lg"> + <div className="rounded-md border border-gray-200 bg-background px-4 py-2 text-lg"> <p className="text-nowrap"> {icon} {name} </p> diff --git a/apps/web/components/dashboard/lists/DeleteListButton.tsx b/apps/web/components/dashboard/lists/DeleteListButton.tsx index 5303b217..f5fcb18b 100644 --- a/apps/web/components/dashboard/lists/DeleteListButton.tsx +++ b/apps/web/components/dashboard/lists/DeleteListButton.tsx @@ -1,5 +1,8 @@ "use client"; +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -10,13 +13,11 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { Trash } from "lucide-react"; -import { useRouter } from "next/navigation"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; -import { ActionButton } from "@/components/ui/action-button"; -import { useState } from "react"; -import { ZBookmarkList } from "@hoarder/trpc/types/lists"; +import { Trash } from "lucide-react"; + +import type { ZBookmarkList } from "@hoarder/trpc/types/lists"; export default function DeleteListButton({ list }: { list: ZBookmarkList }) { const [isDialogOpen, setDialogOpen] = useState(false); diff --git a/apps/web/components/dashboard/lists/ListView.tsx b/apps/web/components/dashboard/lists/ListView.tsx index 2d48d9e3..beeea7f1 100644 --- a/apps/web/components/dashboard/lists/ListView.tsx +++ b/apps/web/components/dashboard/lists/ListView.tsx @@ -1,10 +1,11 @@ "use client"; import BookmarksGrid from "@/components/dashboard/bookmarks/BookmarksGrid"; -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; -import { ZBookmarkListWithBookmarks } from "@hoarder/trpc/types/lists"; import { api } from "@/lib/trpc"; +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; +import type { ZBookmarkListWithBookmarks } from "@hoarder/trpc/types/lists"; + export default function ListView({ bookmarks, list: initialData, diff --git a/apps/web/components/dashboard/search/SearchInput.tsx b/apps/web/components/dashboard/search/SearchInput.tsx index 73d14c90..abb19f5e 100644 --- a/apps/web/components/dashboard/search/SearchInput.tsx +++ b/apps/web/components/dashboard/search/SearchInput.tsx @@ -1,7 +1,7 @@ +import React from "react"; import { Input } from "@/components/ui/input"; import { useDoBookmarkSearch } from "@/lib/hooks/bookmark-search"; import { cn } from "@/lib/utils"; -import React from "react"; const SearchInput = React.forwardRef< HTMLInputElement, diff --git a/apps/web/components/dashboard/settings/AddApiKey.tsx b/apps/web/components/dashboard/settings/AddApiKey.tsx index a4fd9c25..15a78d56 100644 --- a/apps/web/components/dashboard/settings/AddApiKey.tsx +++ b/apps/web/components/dashboard/settings/AddApiKey.tsx @@ -1,17 +1,10 @@ "use client"; +import type { SubmitErrorHandler } from "react-hook-form"; +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form"; - import { Dialog, DialogClose, @@ -22,15 +15,22 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { z } from "zod"; -import { useRouter } from "next/navigation"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm, SubmitErrorHandler } from "react-hook-form"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; -import { useState } from "react"; +import { zodResolver } from "@hookform/resolvers/zod"; import { Check, Copy } from "lucide-react"; -import { ActionButton } from "@/components/ui/action-button"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; function ApiKeySuccess({ apiKey }: { apiKey: string }) { const [isCopied, setCopied] = useState(false); diff --git a/apps/web/components/dashboard/settings/ApiKeySettings.tsx b/apps/web/components/dashboard/settings/ApiKeySettings.tsx index 1598f25f..a3680863 100644 --- a/apps/web/components/dashboard/settings/ApiKeySettings.tsx +++ b/apps/web/components/dashboard/settings/ApiKeySettings.tsx @@ -7,8 +7,9 @@ import { TableRow, } from "@/components/ui/table"; import { api } from "@/server/api/client"; -import DeleteApiKey from "./DeleteApiKey"; + import AddApiKey from "./AddApiKey"; +import DeleteApiKey from "./DeleteApiKey"; export default async function ApiKeys() { const keys = await api.apiKeys.list(); diff --git a/apps/web/components/dashboard/settings/DeleteApiKey.tsx b/apps/web/components/dashboard/settings/DeleteApiKey.tsx index 566136af..091f352c 100644 --- a/apps/web/components/dashboard/settings/DeleteApiKey.tsx +++ b/apps/web/components/dashboard/settings/DeleteApiKey.tsx @@ -1,8 +1,9 @@ "use client"; +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; -import { Trash } from "lucide-react"; - import { Dialog, DialogClose, @@ -13,11 +14,9 @@ import { DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; -import { useRouter } from "next/navigation"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; -import { ActionButton } from "@/components/ui/action-button"; -import { useState } from "react"; +import { Trash } from "lucide-react"; export default function DeleteApiKey({ name, diff --git a/apps/web/components/dashboard/sidebar/AllLists.tsx b/apps/web/components/dashboard/sidebar/AllLists.tsx index a77252d0..34680cdd 100644 --- a/apps/web/components/dashboard/sidebar/AllLists.tsx +++ b/apps/web/components/dashboard/sidebar/AllLists.tsx @@ -1,11 +1,13 @@ "use client"; +import Link from "next/link"; import { api } from "@/lib/trpc"; -import SidebarItem from "./SidebarItem"; -import NewListModal, { useNewListModal } from "./NewListModal"; import { Plus } from "lucide-react"; -import Link from "next/link"; -import { ZBookmarkList } from "@hoarder/trpc/types/lists"; + +import type { ZBookmarkList } from "@hoarder/trpc/types/lists"; + +import NewListModal, { useNewListModal } from "./NewListModal"; +import SidebarItem from "./SidebarItem"; export default function AllLists({ initialData, diff --git a/apps/web/components/dashboard/sidebar/ModileSidebar.tsx b/apps/web/components/dashboard/sidebar/ModileSidebar.tsx index 4bd6a347..3c68433a 100644 --- a/apps/web/components/dashboard/sidebar/ModileSidebar.tsx +++ b/apps/web/components/dashboard/sidebar/ModileSidebar.tsx @@ -1,11 +1,12 @@ -import MobileSidebarItem from "./ModileSidebarItem"; import { - Tag, + ClipboardList, PackageOpen, - Settings, Search, - ClipboardList, + Settings, + Tag, } from "lucide-react"; + +import MobileSidebarItem from "./ModileSidebarItem"; import SidebarProfileOptions from "./SidebarProfileOptions"; export default async function MobileSidebar() { diff --git a/apps/web/components/dashboard/sidebar/ModileSidebarItem.tsx b/apps/web/components/dashboard/sidebar/ModileSidebarItem.tsx index 9389d2e4..d2b4aad3 100644 --- a/apps/web/components/dashboard/sidebar/ModileSidebarItem.tsx +++ b/apps/web/components/dashboard/sidebar/ModileSidebarItem.tsx @@ -1,8 +1,8 @@ "use client"; -import { cn } from "@/lib/utils"; import Link from "next/link"; import { usePathname } from "next/navigation"; +import { cn } from "@/lib/utils"; export default function MobileSidebarItem({ logo, diff --git a/apps/web/components/dashboard/sidebar/NewListModal.tsx b/apps/web/components/dashboard/sidebar/NewListModal.tsx index f51616ed..e244411d 100644 --- a/apps/web/components/dashboard/sidebar/NewListModal.tsx +++ b/apps/web/components/dashboard/sidebar/NewListModal.tsx @@ -1,14 +1,5 @@ "use client"; -import data from "@emoji-mart/data"; -import Picker from "@emoji-mart/react"; - -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; - import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; import { @@ -18,7 +9,6 @@ import { DialogFooter, DialogHeader, DialogTitle, - DialogTrigger, } from "@/components/ui/dialog"; import { Form, @@ -27,15 +17,19 @@ import { FormItem, FormMessage, } from "@/components/ui/form"; - +import { Input } from "@/components/ui/input"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; - -import { z } from "zod"; -import { useForm } from "react-hook-form"; +import data from "@emoji-mart/data"; +import Picker from "@emoji-mart/react"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Input } from "@/components/ui/input"; - +import { useForm } from "react-hook-form"; +import { z } from "zod"; import { create } from "zustand"; export const useNewListModal = create<{ @@ -113,7 +107,7 @@ export default function NewListModal() { <FormItem> <FormControl> <Popover> - <PopoverTrigger className="border-input h-full rounded border px-2 text-2xl"> + <PopoverTrigger className="h-full rounded border border-input px-2 text-2xl"> {field.value} </PopoverTrigger> <PopoverContent> diff --git a/apps/web/components/dashboard/sidebar/Sidebar.tsx b/apps/web/components/dashboard/sidebar/Sidebar.tsx index a5c1d7a5..0351b889 100644 --- a/apps/web/components/dashboard/sidebar/Sidebar.tsx +++ b/apps/web/components/dashboard/sidebar/Sidebar.tsx @@ -1,13 +1,15 @@ -import { Tag, Home, PackageOpen, Settings, Search, Shield } from "lucide-react"; -import { redirect } from "next/navigation"; -import SidebarItem from "./SidebarItem"; -import { getServerAuthSession } from "@/server/auth"; import Link from "next/link"; -import SidebarProfileOptions from "./SidebarProfileOptions"; +import { redirect } from "next/navigation"; import { Separator } from "@/components/ui/separator"; -import AllLists from "./AllLists"; -import serverConfig from "@hoarder/shared/config"; import { api } from "@/server/api/client"; +import { getServerAuthSession } from "@/server/auth"; +import { Home, PackageOpen, Search, Settings, Shield, Tag } from "lucide-react"; + +import serverConfig from "@hoarder/shared/config"; + +import AllLists from "./AllLists"; +import SidebarItem from "./SidebarItem"; +import SidebarProfileOptions from "./SidebarProfileOptions"; export default async function Sidebar() { const session = await getServerAuthSession(); diff --git a/apps/web/components/dashboard/sidebar/SidebarItem.tsx b/apps/web/components/dashboard/sidebar/SidebarItem.tsx index 856bdffd..75a1f6ba 100644 --- a/apps/web/components/dashboard/sidebar/SidebarItem.tsx +++ b/apps/web/components/dashboard/sidebar/SidebarItem.tsx @@ -1,8 +1,8 @@ "use client"; -import { cn } from "@/lib/utils"; import Link from "next/link"; import { usePathname } from "next/navigation"; +import { cn } from "@/lib/utils"; export default function SidebarItem({ name, diff --git a/apps/web/components/signin/CredentialsForm.tsx b/apps/web/components/signin/CredentialsForm.tsx index 5296e163..59dfeb21 100644 --- a/apps/web/components/signin/CredentialsForm.tsx +++ b/apps/web/components/signin/CredentialsForm.tsx @@ -1,8 +1,8 @@ "use client"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ActionButton } from "@/components/ui/action-button"; import { Form, FormControl, @@ -12,13 +12,15 @@ import { FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; -import { ActionButton } from "@/components/ui/action-button"; -import { zSignUpSchema } from "@hoarder/trpc/types/users"; -import { signIn } from "next-auth/react"; -import { useState } from "react"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/lib/trpc"; -import { useRouter } from "next/navigation"; +import { zodResolver } from "@hookform/resolvers/zod"; import { TRPCClientError } from "@trpc/client"; +import { signIn } from "next-auth/react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; + +import { zSignUpSchema } from "@hoarder/trpc/types/users"; const signInSchema = z.object({ email: z.string().email(), diff --git a/apps/web/components/signin/SignInForm.tsx b/apps/web/components/signin/SignInForm.tsx index 7c8f8936..aa70e207 100644 --- a/apps/web/components/signin/SignInForm.tsx +++ b/apps/web/components/signin/SignInForm.tsx @@ -1,6 +1,7 @@ import { getProviders } from "next-auth/react"; -import SignInProviderButton from "./SignInProviderButton"; + import CredentialsForm from "./CredentialsForm"; +import SignInProviderButton from "./SignInProviderButton"; export default async function SignInForm() { const providers = await getProviders(); diff --git a/apps/web/components/signin/SignInProviderButton.tsx b/apps/web/components/signin/SignInProviderButton.tsx index 0831236c..0f208397 100644 --- a/apps/web/components/signin/SignInProviderButton.tsx +++ b/apps/web/components/signin/SignInProviderButton.tsx @@ -1,6 +1,8 @@ "use client"; + +import type { ClientSafeProvider } from "next-auth/react"; import { Button } from "@/components/ui/button"; -import { ClientSafeProvider, signIn } from "next-auth/react"; +import { signIn } from "next-auth/react"; export default function SignInProviderButton({ provider, diff --git a/apps/web/components/ui/action-button.tsx b/apps/web/components/ui/action-button.tsx index 42e16f65..11b02a5f 100644 --- a/apps/web/components/ui/action-button.tsx +++ b/apps/web/components/ui/action-button.tsx @@ -1,4 +1,5 @@ -import { Button, ButtonProps } from "./button"; +import type { ButtonProps } from "./button"; +import { Button } from "./button"; import LoadingSpinner from "./spinner"; export function ActionButton({ diff --git a/apps/web/components/ui/back-button.tsx b/apps/web/components/ui/back-button.tsx index 685930df..46c99f7c 100644 --- a/apps/web/components/ui/back-button.tsx +++ b/apps/web/components/ui/back-button.tsx @@ -1,7 +1,9 @@ "use client"; import { useRouter } from "next/navigation"; -import { Button, ButtonProps } from "./button"; + +import type { ButtonProps } from "./button"; +import { Button } from "./button"; export function BackButton({ ...props }: ButtonProps) { const router = useRouter(); diff --git a/apps/web/components/ui/badge.tsx b/apps/web/components/ui/badge.tsx index c30daca1..7950a5ee 100644 --- a/apps/web/components/ui/badge.tsx +++ b/apps/web/components/ui/badge.tsx @@ -1,19 +1,19 @@ +import type { VariantProps } from "class-variance-authority"; import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; - import { cn } from "@/lib/utils"; +import { cva } from "class-variance-authority"; const badgeVariants = cva( - "focus:ring-ring inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2", + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", { variants: { variant: { default: - "bg-primary text-primary-foreground hover:bg-primary/80 border-transparent", + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent", + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent", + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", outline: "text-foreground", }, }, diff --git a/apps/web/components/ui/button.tsx b/apps/web/components/ui/button.tsx index 79b45fa0..5ed8df91 100644 --- a/apps/web/components/ui/button.tsx +++ b/apps/web/components/ui/button.tsx @@ -1,11 +1,11 @@ +import type { VariantProps } from "class-variance-authority"; import * as React from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { cva, type VariantProps } from "class-variance-authority"; - import { cn } from "@/lib/utils"; +import { Slot } from "@radix-ui/react-slot"; +import { cva } from "class-variance-authority"; const buttonVariants = cva( - "ring-offset-background focus-visible:ring-ring inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { @@ -13,7 +13,7 @@ const buttonVariants = cva( destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: - "border-input bg-background hover:bg-accent hover:text-accent-foreground border", + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", diff --git a/apps/web/components/ui/card.tsx b/apps/web/components/ui/card.tsx index f4e57996..9df66460 100644 --- a/apps/web/components/ui/card.tsx +++ b/apps/web/components/ui/card.tsx @@ -1,5 +1,4 @@ import * as React from "react"; - import { cn } from "@/lib/utils"; const Card = React.forwardRef< @@ -9,7 +8,7 @@ const Card = React.forwardRef< <div ref={ref} className={cn( - "bg-card text-card-foreground rounded-lg border shadow-sm", + "rounded-lg border bg-card text-card-foreground shadow-sm", className, )} {...props} @@ -33,6 +32,7 @@ const CardTitle = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement> >(({ className, ...props }, ref) => ( + // eslint-disable-next-line jsx-a11y/heading-has-content <h3 ref={ref} className={cn( @@ -50,7 +50,7 @@ const CardDescription = React.forwardRef< >(({ className, ...props }, ref) => ( <p ref={ref} - className={cn("text-muted-foreground text-sm", className)} + className={cn("text-sm text-muted-foreground", className)} {...props} /> )); diff --git a/apps/web/components/ui/dialog.tsx b/apps/web/components/ui/dialog.tsx index 8fe3fe35..8e0c3c6c 100644 --- a/apps/web/components/ui/dialog.tsx +++ b/apps/web/components/ui/dialog.tsx @@ -1,11 +1,10 @@ "use client"; import * as React from "react"; +import { cn } from "@/lib/utils"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { X } from "lucide-react"; -import { cn } from "@/lib/utils"; - const Dialog = DialogPrimitive.Root; const DialogTrigger = DialogPrimitive.Trigger; @@ -21,7 +20,7 @@ const DialogOverlay = React.forwardRef< <DialogPrimitive.Overlay ref={ref} className={cn( - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80", + "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className, )} {...props} @@ -38,13 +37,13 @@ const DialogContent = React.forwardRef< <DialogPrimitive.Content ref={ref} className={cn( - "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg", + "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className, )} {...props} > {children} - <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none"> + <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> <X className="size-4" /> <span className="sr-only">Close</span> </DialogPrimitive.Close> @@ -102,7 +101,7 @@ const DialogDescription = React.forwardRef< >(({ className, ...props }, ref) => ( <DialogPrimitive.Description ref={ref} - className={cn("text-muted-foreground text-sm", className)} + className={cn("text-sm text-muted-foreground", className)} {...props} /> )); diff --git a/apps/web/components/ui/dropdown-menu.tsx b/apps/web/components/ui/dropdown-menu.tsx index 3a9a2ff7..2bab577e 100644 --- a/apps/web/components/ui/dropdown-menu.tsx +++ b/apps/web/components/ui/dropdown-menu.tsx @@ -1,11 +1,10 @@ "use client"; import * as React from "react"; +import { cn } from "@/lib/utils"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import { Check, ChevronRight, Circle } from "lucide-react"; -import { cn } from "@/lib/utils"; - const DropdownMenu = DropdownMenuPrimitive.Root; const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; @@ -27,7 +26,7 @@ const DropdownMenuSubTrigger = React.forwardRef< <DropdownMenuPrimitive.SubTrigger ref={ref} className={cn( - "focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none", + "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent", inset && "pl-8", className, )} @@ -47,7 +46,7 @@ const DropdownMenuSubContent = React.forwardRef< <DropdownMenuPrimitive.SubContent ref={ref} className={cn( - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg", + "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} @@ -65,7 +64,7 @@ const DropdownMenuContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md", + "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} @@ -83,7 +82,7 @@ const DropdownMenuItem = React.forwardRef< <DropdownMenuPrimitive.Item ref={ref} className={cn( - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", inset && "pl-8", className, )} @@ -99,7 +98,7 @@ const DropdownMenuCheckboxItem = React.forwardRef< <DropdownMenuPrimitive.CheckboxItem ref={ref} className={cn( - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className, )} checked={checked} @@ -123,7 +122,7 @@ const DropdownMenuRadioItem = React.forwardRef< <DropdownMenuPrimitive.RadioItem ref={ref} className={cn( - "focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className, )} {...props} @@ -162,7 +161,7 @@ const DropdownMenuSeparator = React.forwardRef< >(({ className, ...props }, ref) => ( <DropdownMenuPrimitive.Separator ref={ref} - className={cn("bg-muted -mx-1 my-1 h-px", className)} + className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} /> )); diff --git a/apps/web/components/ui/form.tsx b/apps/web/components/ui/form.tsx index e62e10e9..20ce3c4b 100644 --- a/apps/web/components/ui/form.tsx +++ b/apps/web/components/ui/form.tsx @@ -1,26 +1,19 @@ +import type * as LabelPrimitive from "@radix-ui/react-label"; +import type { ControllerProps, FieldPath, FieldValues } from "react-hook-form"; import * as React from "react"; -import * as LabelPrimitive from "@radix-ui/react-label"; -import { Slot } from "@radix-ui/react-slot"; -import { - Controller, - ControllerProps, - FieldPath, - FieldValues, - FormProvider, - useFormContext, -} from "react-hook-form"; - -import { cn } from "@/lib/utils"; import { Label } from "@/components/ui/label"; +import { cn } from "@/lib/utils"; +import { Slot } from "@radix-ui/react-slot"; +import { Controller, FormProvider, useFormContext } from "react-hook-form"; const Form = FormProvider; -type FormFieldContextValue< +interface FormFieldContextValue< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>, -> = { +> { name: TName; -}; +} const FormFieldContext = React.createContext<FormFieldContextValue>( {} as FormFieldContextValue, @@ -62,9 +55,9 @@ const useFormField = () => { }; }; -type FormItemContextValue = { +interface FormItemContextValue { id: string; -}; +} const FormItemContext = React.createContext<FormItemContextValue>( {} as FormItemContextValue, @@ -134,7 +127,7 @@ const FormDescription = React.forwardRef< <p ref={ref} id={formDescriptionId} - className={cn("text-muted-foreground text-sm", className)} + className={cn("text-sm text-muted-foreground", className)} {...props} /> ); @@ -156,7 +149,7 @@ const FormMessage = React.forwardRef< <p ref={ref} id={formMessageId} - className={cn("text-destructive text-sm font-medium", className)} + className={cn("text-sm font-medium text-destructive", className)} {...props} > {body} diff --git a/apps/web/components/ui/imageCard.tsx b/apps/web/components/ui/imageCard.tsx index f10ebdb5..e4941733 100644 --- a/apps/web/components/ui/imageCard.tsx +++ b/apps/web/components/ui/imageCard.tsx @@ -1,5 +1,4 @@ import * as React from "react"; - import { cn } from "@/lib/utils"; export function ImageCard({ diff --git a/apps/web/components/ui/input.tsx b/apps/web/components/ui/input.tsx index 21aac7ad..5543446c 100644 --- a/apps/web/components/ui/input.tsx +++ b/apps/web/components/ui/input.tsx @@ -1,9 +1,7 @@ import * as React from "react"; - import { cn } from "@/lib/utils"; -export interface InputProps - extends React.InputHTMLAttributes<HTMLInputElement> {} +export type InputProps = React.InputHTMLAttributes<HTMLInputElement>; const Input = React.forwardRef<HTMLInputElement, InputProps>( ({ className, type, ...props }, ref) => { @@ -11,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>( <input type={type} className={cn( - "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-full rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", + "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className, )} ref={ref} diff --git a/apps/web/components/ui/label.tsx b/apps/web/components/ui/label.tsx index 84f8b0c7..d12e2c2c 100644 --- a/apps/web/components/ui/label.tsx +++ b/apps/web/components/ui/label.tsx @@ -1,10 +1,10 @@ "use client"; +import type { VariantProps } from "class-variance-authority"; import * as React from "react"; -import * as LabelPrimitive from "@radix-ui/react-label"; -import { cva, type VariantProps } from "class-variance-authority"; - import { cn } from "@/lib/utils"; +import * as LabelPrimitive from "@radix-ui/react-label"; +import { cva } from "class-variance-authority"; const labelVariants = cva( "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", diff --git a/apps/web/components/ui/popover.tsx b/apps/web/components/ui/popover.tsx index a361ba7d..30645cc8 100644 --- a/apps/web/components/ui/popover.tsx +++ b/apps/web/components/ui/popover.tsx @@ -1,9 +1,8 @@ "use client"; import * as React from "react"; -import * as PopoverPrimitive from "@radix-ui/react-popover"; - import { cn } from "@/lib/utils"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; const Popover = PopoverPrimitive.Root; @@ -19,7 +18,7 @@ const PopoverContent = React.forwardRef< align={align} sideOffset={sideOffset} className={cn( - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none", + "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} diff --git a/apps/web/components/ui/scroll-area.tsx b/apps/web/components/ui/scroll-area.tsx index 32cb6022..9d77ecd1 100644 --- a/apps/web/components/ui/scroll-area.tsx +++ b/apps/web/components/ui/scroll-area.tsx @@ -1,9 +1,8 @@ "use client"; import * as React from "react"; -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; - import { cn } from "@/lib/utils"; +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"; const ScrollArea = React.forwardRef< React.ElementRef<typeof ScrollAreaPrimitive.Root>, @@ -40,7 +39,7 @@ const ScrollBar = React.forwardRef< )} {...props} > - <ScrollAreaPrimitive.ScrollAreaThumb className="bg-border relative flex-1 rounded-full" /> + <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" /> </ScrollAreaPrimitive.ScrollAreaScrollbar> )); ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; diff --git a/apps/web/components/ui/select.tsx b/apps/web/components/ui/select.tsx index efd4ff1e..9895e94a 100644 --- a/apps/web/components/ui/select.tsx +++ b/apps/web/components/ui/select.tsx @@ -1,11 +1,10 @@ "use client"; import * as React from "react"; +import { cn } from "@/lib/utils"; import * as SelectPrimitive from "@radix-ui/react-select"; import { Check, ChevronDown, ChevronUp } from "lucide-react"; -import { cn } from "@/lib/utils"; - const Select = SelectPrimitive.Root; const SelectGroup = SelectPrimitive.Group; @@ -19,7 +18,7 @@ const SelectTrigger = React.forwardRef< <SelectPrimitive.Trigger ref={ref} className={cn( - "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus:ring-ring flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", + "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", className, )} {...props} @@ -75,7 +74,7 @@ const SelectContent = React.forwardRef< <SelectPrimitive.Content ref={ref} className={cn( - "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border shadow-md", + "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1", className, @@ -118,7 +117,7 @@ const SelectItem = React.forwardRef< <SelectPrimitive.Item ref={ref} className={cn( - "focus:bg-accent focus:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50", + "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className, )} {...props} @@ -140,7 +139,7 @@ const SelectSeparator = React.forwardRef< >(({ className, ...props }, ref) => ( <SelectPrimitive.Separator ref={ref} - className={cn("bg-muted -mx-1 my-1 h-px", className)} + className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} /> )); diff --git a/apps/web/components/ui/separator.tsx b/apps/web/components/ui/separator.tsx index 3b9f2b84..09303128 100644 --- a/apps/web/components/ui/separator.tsx +++ b/apps/web/components/ui/separator.tsx @@ -1,9 +1,8 @@ "use client"; import * as React from "react"; -import * as SeparatorPrimitive from "@radix-ui/react-separator"; - import { cn } from "@/lib/utils"; +import * as SeparatorPrimitive from "@radix-ui/react-separator"; const Separator = React.forwardRef< React.ElementRef<typeof SeparatorPrimitive.Root>, @@ -18,7 +17,7 @@ const Separator = React.forwardRef< decorative={decorative} orientation={orientation} className={cn( - "bg-border shrink-0", + "shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className, )} diff --git a/apps/web/components/ui/skeleton.tsx b/apps/web/components/ui/skeleton.tsx index 5fab2023..2cdf440d 100644 --- a/apps/web/components/ui/skeleton.tsx +++ b/apps/web/components/ui/skeleton.tsx @@ -6,7 +6,7 @@ function Skeleton({ }: React.HTMLAttributes<HTMLDivElement>) { return ( <div - className={cn("bg-muted animate-pulse rounded-md", className)} + className={cn("animate-pulse rounded-md bg-muted", className)} {...props} /> ); diff --git a/apps/web/components/ui/table.tsx b/apps/web/components/ui/table.tsx index 0fa9288e..95b43b8c 100644 --- a/apps/web/components/ui/table.tsx +++ b/apps/web/components/ui/table.tsx @@ -1,5 +1,4 @@ import * as React from "react"; - import { cn } from "@/lib/utils"; const Table = React.forwardRef< @@ -43,7 +42,7 @@ const TableFooter = React.forwardRef< <tfoot ref={ref} className={cn( - "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", + "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className, )} {...props} @@ -58,7 +57,7 @@ const TableRow = React.forwardRef< <tr ref={ref} className={cn( - "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", + "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className, )} {...props} @@ -73,7 +72,7 @@ const TableHead = React.forwardRef< <th ref={ref} className={cn( - "text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0", + "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0", className, )} {...props} @@ -99,7 +98,7 @@ const TableCaption = React.forwardRef< >(({ className, ...props }, ref) => ( <caption ref={ref} - className={cn("text-muted-foreground mt-4 text-sm", className)} + className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} /> )); diff --git a/apps/web/components/ui/tabs.tsx b/apps/web/components/ui/tabs.tsx index 990017db..4c1b0ab1 100644 --- a/apps/web/components/ui/tabs.tsx +++ b/apps/web/components/ui/tabs.tsx @@ -1,9 +1,8 @@ "use client"; import * as React from "react"; -import * as TabsPrimitive from "@radix-ui/react-tabs"; - import { cn } from "@/lib/utils"; +import * as TabsPrimitive from "@radix-ui/react-tabs"; const Tabs = TabsPrimitive.Root; @@ -14,7 +13,7 @@ const TabsList = React.forwardRef< <TabsPrimitive.List ref={ref} className={cn( - "bg-muted text-muted-foreground inline-flex h-10 items-center justify-center rounded-md p-1", + "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className, )} {...props} @@ -29,7 +28,7 @@ const TabsTrigger = React.forwardRef< <TabsPrimitive.Trigger ref={ref} className={cn( - "ring-offset-background focus-visible:ring-ring data-[state=active]:bg-background data-[state=active]:text-foreground inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm", + "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm", className, )} {...props} @@ -44,7 +43,7 @@ const TabsContent = React.forwardRef< <TabsPrimitive.Content ref={ref} className={cn( - "ring-offset-background focus-visible:ring-ring mt-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2", + "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", className, )} {...props} diff --git a/apps/web/components/ui/textarea.tsx b/apps/web/components/ui/textarea.tsx index a0de3371..98d704ae 100644 --- a/apps/web/components/ui/textarea.tsx +++ b/apps/web/components/ui/textarea.tsx @@ -1,16 +1,14 @@ import * as React from "react"; - import { cn } from "@/lib/utils"; -export interface TextareaProps - extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {} +export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>; const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( ({ className, ...props }, ref) => { return ( <textarea className={cn( - "border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", + "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", className, )} ref={ref} diff --git a/apps/web/components/ui/toast.tsx b/apps/web/components/ui/toast.tsx index 0d162dca..16c2f76f 100644 --- a/apps/web/components/ui/toast.tsx +++ b/apps/web/components/ui/toast.tsx @@ -1,10 +1,10 @@ +import type { VariantProps } from "class-variance-authority"; import * as React from "react"; +import { cn } from "@/lib/utils"; import * as ToastPrimitives from "@radix-ui/react-toast"; -import { cva, type VariantProps } from "class-variance-authority"; +import { cva } from "class-variance-authority"; import { X } from "lucide-react"; -import { cn } from "@/lib/utils"; - const ToastProvider = ToastPrimitives.Provider; const ToastViewport = React.forwardRef< @@ -23,13 +23,13 @@ const ToastViewport = React.forwardRef< ToastViewport.displayName = ToastPrimitives.Viewport.displayName; const toastVariants = cva( - "data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none", + "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", { variants: { variant: { - default: "bg-background text-foreground border", + default: "border bg-background text-foreground", destructive: - "destructive border-destructive bg-destructive text-destructive-foreground group", + "destructive group border-destructive bg-destructive text-destructive-foreground", }, }, defaultVariants: { @@ -60,7 +60,7 @@ const ToastAction = React.forwardRef< <ToastPrimitives.Action ref={ref} className={cn( - "ring-offset-background hover:bg-secondary focus:ring-ring group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive", className, )} {...props} @@ -75,7 +75,7 @@ const ToastClose = React.forwardRef< <ToastPrimitives.Close ref={ref} className={cn( - "text-foreground/50 hover:text-foreground absolute right-2 top-2 rounded-md p-1 opacity-0 transition-opacity focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", + "absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", className, )} toast-close="" diff --git a/apps/web/components/ui/use-toast.ts b/apps/web/components/ui/use-toast.ts index 5491e140..5ec5aa36 100644 --- a/apps/web/components/ui/use-toast.ts +++ b/apps/web/components/ui/use-toast.ts @@ -1,7 +1,6 @@ // Inspired by react-hot-toast library -import * as React from "react"; - import type { ToastActionElement, ToastProps } from "@/components/ui/toast"; +import * as React from "react"; const TOAST_LIMIT = 1; const TOAST_REMOVE_DELAY = 1000000; @@ -124,7 +123,7 @@ export const reducer = (state: State, action: Action): State => { } }; -const listeners: Array<(_state: State) => void> = []; +const listeners: ((_state: State) => void)[] = []; let memoryState: State = { toasts: [] }; diff --git a/apps/web/lib/bookmarkUtils.tsx b/apps/web/lib/bookmarkUtils.tsx index a2828c29..fbb7c7df 100644 --- a/apps/web/lib/bookmarkUtils.tsx +++ b/apps/web/lib/bookmarkUtils.tsx @@ -1,4 +1,4 @@ -import { ZBookmark } from "@hoarder/trpc/types/bookmarks"; +import type { ZBookmark } from "@hoarder/trpc/types/bookmarks"; const MAX_LOADING_MSEC = 30 * 1000; diff --git a/apps/web/lib/hooks/bookmark-search.ts b/apps/web/lib/hooks/bookmark-search.ts index 738e1bd8..1971e79e 100644 --- a/apps/web/lib/hooks/bookmark-search.ts +++ b/apps/web/lib/hooks/bookmark-search.ts @@ -1,11 +1,11 @@ import { useEffect, useState } from "react"; -import { api } from "@/lib/trpc"; import { useRouter, useSearchParams } from "next/navigation"; +import { api } from "@/lib/trpc"; import { keepPreviousData } from "@tanstack/react-query"; function useSearchQuery() { const searchParams = useSearchParams(); - const searchQuery = searchParams.get("q") || ""; + const searchQuery = searchParams.get("q") ?? ""; return { searchQuery }; } diff --git a/apps/web/lib/providers.tsx b/apps/web/lib/providers.tsx index 5c4649b5..db51c361 100644 --- a/apps/web/lib/providers.tsx +++ b/apps/web/lib/providers.tsx @@ -1,13 +1,13 @@ "use client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import type { Session } from "next-auth"; import React, { useState } from "react"; -import { api } from "./trpc"; -import { loggerLink } from "@trpc/client"; -import { httpBatchLink } from "@trpc/client"; -import superjson from "superjson"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { httpBatchLink, loggerLink } from "@trpc/client"; import { SessionProvider } from "next-auth/react"; -import { Session } from "next-auth"; +import superjson from "superjson"; + +import { api } from "./trpc"; function makeQueryClient() { return new QueryClient({ diff --git a/apps/web/lib/trpc.tsx b/apps/web/lib/trpc.tsx index 79a2a9fe..99fdd8b5 100644 --- a/apps/web/lib/trpc.tsx +++ b/apps/web/lib/trpc.tsx @@ -1,5 +1,7 @@ "use client"; -import type { AppRouter } from "@hoarder/trpc/routers/_app"; + import { createTRPCReact } from "@trpc/react-query"; +import type { AppRouter } from "@hoarder/trpc/routers/_app"; + export const api = createTRPCReact<AppRouter>(); diff --git a/apps/web/lib/utils.ts b/apps/web/lib/utils.ts index 365058ce..88283f01 100644 --- a/apps/web/lib/utils.ts +++ b/apps/web/lib/utils.ts @@ -1,4 +1,5 @@ -import { type ClassValue, clsx } from "clsx"; +import type { ClassValue } from "clsx"; +import { clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index fa0757dd..041ab6b3 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -39,11 +39,7 @@ const nextConfig = withPWA({ ]; }, - transpilePackages: [ - "@hoarder/shared", - "@hoarder/db", - "@hoarder/trpc", - ], + transpilePackages: ["@hoarder/shared", "@hoarder/db", "@hoarder/trpc"], /** We already do linting and typechecking as separate tasks in CI */ eslint: { ignoreDuringBuilds: true }, diff --git a/apps/web/server/api/client.ts b/apps/web/server/api/client.ts index 88ea7a0e..8b414d39 100644 --- a/apps/web/server/api/client.ts +++ b/apps/web/server/api/client.ts @@ -1,7 +1,8 @@ -import { appRouter } from "@hoarder/trpc/routers/_app"; import { getServerAuthSession } from "@/server/auth"; -import { Context, createCallerFactory } from "@hoarder/trpc"; + import { db } from "@hoarder/db"; +import { Context, createCallerFactory } from "@hoarder/trpc"; +import { appRouter } from "@hoarder/trpc/routers/_app"; export const createContext = async (database?: typeof db): Promise<Context> => { const session = await getServerAuthSession(); diff --git a/apps/web/server/auth.ts b/apps/web/server/auth.ts index 950443b9..767bc7e8 100644 --- a/apps/web/server/auth.ts +++ b/apps/web/server/auth.ts @@ -1,15 +1,18 @@ -import NextAuth, { NextAuthOptions, getServerSession } from "next-auth"; import type { Adapter } from "next-auth/adapters"; +import { DrizzleAdapter } from "@auth/drizzle-adapter"; +import NextAuth, { + DefaultSession, + getServerSession, + NextAuthOptions, +} from "next-auth"; import AuthentikProvider from "next-auth/providers/authentik"; -import serverConfig from "@hoarder/shared/config"; -import { validatePassword } from "@hoarder/trpc/auth"; -import { db } from "@hoarder/db"; -import { DefaultSession } from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; -import { DrizzleAdapter } from "@auth/drizzle-adapter"; - import { Provider } from "next-auth/providers/index"; +import { db } from "@hoarder/db"; +import serverConfig from "@hoarder/shared/config"; +import { validatePassword } from "@hoarder/trpc/auth"; + declare module "next-auth/jwt" { export interface JWT { user: { diff --git a/apps/web/vitest.config.ts b/apps/web/vitest.config.ts index c3d02f71..41fd70c4 100644 --- a/apps/web/vitest.config.ts +++ b/apps/web/vitest.config.ts @@ -1,7 +1,7 @@ /// <reference types="vitest" /> -import { defineConfig } from "vitest/config"; import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig } from "vitest/config"; // https://vitejs.dev/config/ export default defineConfig({ |
