diff --git a/app/routes/_blog.blog.load-more-posts.tsx b/app/routes/_blog.blog.load-more-posts.tsx index 23dd7ab..91467ce 100644 --- a/app/routes/_blog.blog.load-more-posts.tsx +++ b/app/routes/_blog.blog.load-more-posts.tsx @@ -69,5 +69,5 @@ export async function action({ request }: ActionFunctionArgs) { } break; } - return json({}); -} + +} \ No newline at end of file diff --git a/app/services/types.ts b/app/services/types.ts index 102728c..f4b8d43 100644 --- a/app/services/types.ts +++ b/app/services/types.ts @@ -1,7 +1,5 @@ -import type { LoaderFunction } from "@remix-run/server-runtime"; +import type { LoaderFunction, SerializeFrom } from "@remix-run/server-runtime"; -export type UwrapJSONLoaderData = Awaited< - ReturnType>["json"]> ->; +export type UwrapJSONLoaderData = SerializeFrom; export type UwrapLoaderData = Awaited>; diff --git a/app/services/utils.ts b/app/services/utils.ts index 7ea8c2b..f75622a 100644 --- a/app/services/utils.ts +++ b/app/services/utils.ts @@ -31,13 +31,11 @@ export function safeRedirect( * @param {string} id The route id * @returns {JSON|undefined} The router data or undefined if not found */ -export function useMatchesData( - id: string -): Record | undefined { +export function useMatchesData(id: string): unknown | undefined { const matchingRoutes = useMatches(); const route = useMemo( () => matchingRoutes.find((route) => route.id === id), - [matchingRoutes, id] + [matchingRoutes, id], ); return route?.data; } diff --git a/app/ui/components/alert-dialog.tsx b/app/ui/components/alert-dialog.tsx index a80c532..0b1919f 100644 --- a/app/ui/components/alert-dialog.tsx +++ b/app/ui/components/alert-dialog.tsx @@ -2,35 +2,24 @@ import * as React from "react"; import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; -import { cn } from "~/ui/utils"; import { buttonVariants } from "~/ui/components/button"; +import { cn } from "~/ui/utils"; const AlertDialog = AlertDialogPrimitive.Root; const AlertDialogTrigger = AlertDialogPrimitive.Trigger; -const AlertDialogPortal = ({ - className, - children, - ...props -}: AlertDialogPrimitive.AlertDialogPortalProps) => ( - -
- {children} -
-
-); -AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName; +const AlertDialogPortal = AlertDialogPrimitive.Portal; const AlertDialogOverlay = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( +>(({ className, ...props }, ref) => ( @@ -63,7 +52,7 @@ const AlertDialogHeader = ({
@@ -77,7 +66,7 @@ const AlertDialogFooter = ({
@@ -121,6 +110,19 @@ const AlertDialogAction = React.forwardRef< )); AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; +const AlertDialogDestructiveAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDestructiveAction.displayName = + AlertDialogPrimitive.Action.displayName; + const AlertDialogCancel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef @@ -130,7 +132,7 @@ const AlertDialogCancel = React.forwardRef< className={cn( buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", - className + className, )} {...props} /> @@ -139,6 +141,8 @@ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; export { AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, @@ -147,4 +151,5 @@ export { AlertDialogDescription, AlertDialogAction, AlertDialogCancel, + AlertDialogDestructiveAction, }; diff --git a/app/ui/components/command-bar.tsx b/app/ui/components/command-bar.tsx index 22227e7..17b1b44 100644 --- a/app/ui/components/command-bar.tsx +++ b/app/ui/components/command-bar.tsx @@ -22,12 +22,18 @@ import { CommandSeparator, } from "~/ui/components/command"; -export const CommandBar = () => { +export function CommandBar< + TData extends { + tags: Tag[]; + authors: Author[]; + posts: Post[] + }, +>() { const [open, setOpen] = useState(false); const commandRef = useRef(null); const navigate = useNavigate(); const navigation = useNavigation(); - const command = useFetcher(); + const command = useFetcher(); const [pages, setPages] = useState([]); const page = pages[pages.length - 1]; const [search, setSearch] = useState(""); diff --git a/app/ui/components/dialog.tsx b/app/ui/components/dialog.tsx index 3781b43..f1b5cc6 100644 --- a/app/ui/components/dialog.tsx +++ b/app/ui/components/dialog.tsx @@ -3,24 +3,16 @@ import * as React from "react"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { X } from "lucide-react"; + import { cn } from "~/ui/utils"; const Dialog = DialogPrimitive.Root; const DialogTrigger = DialogPrimitive.Trigger; -const DialogPortal = ({ - className, - children, - ...props -}: DialogPrimitive.DialogPortalProps) => ( - -
- {children} -
-
-); -DialogPortal.displayName = DialogPrimitive.Portal.displayName; +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; const DialogOverlay = React.forwardRef< React.ElementRef, @@ -29,8 +21,8 @@ const DialogOverlay = React.forwardRef< @@ -46,8 +38,8 @@ const DialogContent = React.forwardRef< @@ -68,7 +60,7 @@ const DialogHeader = ({
@@ -82,7 +74,7 @@ const DialogFooter = ({
@@ -97,7 +89,7 @@ const DialogTitle = React.forwardRef< ref={ref} className={cn( "text-lg font-semibold leading-none tracking-tight", - className + className, )} {...props} /> @@ -118,7 +110,10 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName; export { Dialog, + DialogPortal, + DialogOverlay, DialogTrigger, + DialogClose, DialogContent, DialogHeader, DialogFooter, diff --git a/app/ui/components/layout/navbar.tsx b/app/ui/components/layout/navbar.tsx index 0837b2d..bf5339f 100644 --- a/app/ui/components/layout/navbar.tsx +++ b/app/ui/components/layout/navbar.tsx @@ -177,7 +177,7 @@ export const Navbar = ({ - + {settings.title} {settings.description} diff --git a/app/ui/components/posts/posts-list.tsx b/app/ui/components/posts/posts-list.tsx index 51fad6e..d1df906 100644 --- a/app/ui/components/posts/posts-list.tsx +++ b/app/ui/components/posts/posts-list.tsx @@ -4,7 +4,8 @@ import { useFetcher } from "@remix-run/react"; import { AuthenticityTokenInput } from "remix-utils/csrf/react"; import { cn } from "~/ui/utils"; -import { Button } from "~/ui/components";; +import { Button } from "~/ui/components"; +import { type SerializeFrom } from "@remix-run/server-runtime"; export type PostsListProps = { posts: TPostPreview[]; @@ -14,6 +15,11 @@ export type PostsListProps = { className?: string; }; +export type TT = SerializeFrom<{ + posts: TPostPreview[]; + pagination?: { page: number; pages: number; next: number | null } +}> + export const PostsList = ({ posts, pagination = { page: 1, pages: 1, next: null }, @@ -24,13 +30,13 @@ export const PostsList = ({ const [page, setPage] = useState(pagination.page); const [next, setNext] = useState(pagination.next); const [morePosts, setMorePosts] = useState([]); - const paginate = useFetcher(); + const paginate = useFetcher(); useEffect(() => { if (paginate.state === "idle" && paginate.data && paginate.data.posts) { - setMorePosts((prev) => [...prev, ...paginate.data.posts]); - setPage(paginate.data.pagination.page); - setNext(paginate.data.pagination.next); + setMorePosts((prev) => [...prev, ...paginate.data?.posts ?? []]); + setPage(paginate.data.pagination?.page ?? 0); + setNext(paginate.data.pagination?.next ?? null); } }, [paginate.state, paginate.data]); diff --git a/app/ui/components/sheet.tsx b/app/ui/components/sheet.tsx index fe22365..9a2a5a6 100644 --- a/app/ui/components/sheet.tsx +++ b/app/ui/components/sheet.tsx @@ -4,48 +4,25 @@ import * as React from "react"; import * as SheetPrimitive from "@radix-ui/react-dialog"; import { cva, type VariantProps } from "class-variance-authority"; import { X } from "lucide-react"; + import { cn } from "~/ui/utils"; const Sheet = SheetPrimitive.Root; const SheetTrigger = SheetPrimitive.Trigger; -const portalVariants = cva("fixed inset-0 z-50 flex", { - variants: { - position: { - top: "items-start", - bottom: "items-end", - left: "justify-start", - right: "justify-end", - }, - }, - defaultVariants: { position: "right" }, -}); +const SheetClose = SheetPrimitive.Close; -interface SheetPortalProps - extends SheetPrimitive.DialogPortalProps, - VariantProps {} - -const SheetPortal = ({ - position, - className, - children, - ...props -}: SheetPortalProps) => ( - -
{children}
-
-); -SheetPortal.displayName = SheetPrimitive.Portal.displayName; +const SheetPortal = SheetPrimitive.Portal; const SheetOverlay = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( +>(({ className, ...props }, ref) => ( , VariantProps {} const SheetContent = React.forwardRef< React.ElementRef, - DialogContentProps ->(({ position, size, className, children, ...props }, ref) => ( - + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + {children} @@ -173,7 +81,7 @@ const SheetHeader = ({
@@ -187,7 +95,7 @@ const SheetFooter = ({
@@ -220,7 +128,10 @@ SheetDescription.displayName = SheetPrimitive.Description.displayName; export { Sheet, + SheetPortal, + SheetOverlay, SheetTrigger, + SheetClose, SheetContent, SheetHeader, SheetFooter,