🎃
【Convex】NextJs14 と Convex【#26 Convex Card Actions】
【#26 Convex Card Actions】
YouTube: https://youtu.be/UOvg9ldY-OQ
今回はカードのアップデートとデリートの
メニューを実装します。
npx shadcn-ui@latest add dropdown-menu
app/(main)/_components/card/index.tsx
"use client";
import Image from "next/image";
import { useAuth } from "@clerk/nextjs";
import { formatDistanceToNow } from "date-fns";
import { Footer } from "./footer";
import { Overlay } from "./overlay";
import { CardActions } from "./card-actions";
import { MoreHorizontal } from "lucide-react";
interface Props {
id: string;
title: string;
imageUrl: string;
authorId: string;
authorName: string;
createdAt: number;
orgId: string;
cardType: string;
}
export const Card = ({
id,
title,
imageUrl,
authorId,
authorName,
createdAt,
orgId,
cardType,
}: Props) => {
const { userId } = useAuth();
const authorLabel = userId === authorId ? "You" : authorName;
const createdAtLabel = formatDistanceToNow(createdAt, { addSuffix: true });
return (
<div className="group aspect-[100/128] border rounded-lg flex flex-col justify-between overflow-hidden">
<div className="relative flex-1 bg-slate-300">
<Image src={imageUrl} alt={title} fill className="object-cover" />
<Overlay />
<CardActions>
<button className="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity px-3 py-2 outline-none">
<MoreHorizontal className="text-white opacity-75 hover:opacity-100 transition-opacity" />
</button>
</CardActions>
</div>
<Footer
title={title}
authorLabel={authorLabel}
type={cardType}
createdAtLabel={createdAtLabel}
/>
</div>
);
};
app/(main)/_components/card/overlay.tsx
export const Overlay = () => {
return (
<div className="opacity-0 group-hover:opacity-50 transition-opacity h-full w-full bg-black" />
);
};
app/(main)/_components/card/card-actions.tsx
"use client";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Pencil, Trash2 } from "lucide-react";
interface Props {
children: React.ReactNode;
}
export const CardActions = ({ children }: Props) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem className="p-3 cursor-pointer">
<Pencil className="h-4 w-4 mr-2" /> Rename
</DropdownMenuItem>
<DropdownMenuItem className="p-3 cursor-pointer">
<Trash2 className="h-4 w-4 mr-2" /> Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};
Discussion