@enesdmc
This component is built using Next.js and React frameworks, creating a modern, performance-oriented structure. Tailwind CSS is utilized for rapid and customizable styling, while TypeScript ensures type safety. Additionally, the Framer Motion package is used for animation effects, Lucide-react for icons, and next-themes for theme management. These packages provide essential functions that enhance the user experience and make the project more dynamic.
To install the Publish Post Card component run:
bun add framer-motion
bun add lucide-react
Animations make the component more dynamic and encourage user interaction. Below are explanations of what each type of animation does:
containerVariants
: Used when the component loads. It gradually moves upward and becomes visible.
itemVariants
: Ensures each child element, especially icons, appears in sequence with animations.
iconButtonVariants
: Provides visual feedback by enlarging or shrinking icons when hovered or clicked.
publishButtonVariants
: Slightly enlarges and shrinks the Publish button when hovered or clicked.
"use client"
import { EllipsisVertical, Mic, Paperclip, Video, X } from "lucide-react" // Importing icons from lucide-react
import Image from "next/image" // Importing Image component from next/image
import React from "react"
import { motion } from "framer-motion" // Importing motion components from framer-motion
const PublishPostCard = () => {
const containerVariants = { // Container variants for animation
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.6,
when: "beforeChildren",
staggerChildren: 0.1,
},
},
}
const itemVariants = { // Item variants for animation
hidden: { opacity: 0, x: -20 },
visible: {
opacity: 1,
x: 0,
transition: { duration: 0.3 },
},
}
const iconButtonVariants = { // Icon button variants for animation
hover: {
scale: 1.1,
transition: { type: "spring", stiffness: 400, damping: 10 },
},
tap: { scale: 0.95 },
}
const publishButtonVariants = { // Publish button variants for animation
hover: {
scale: 1.05,
transition: { type: "spring", stiffness: 400, damping: 10 },
},
tap: { scale: 0.98 },
}
return (
<motion.div
className="w-[350px] bg-white dark:bg-gray-900 shadow-2xl p-5 rounded-3xl"
variants={containerVariants}
initial="hidden"
animate="visible"
>
{/* Header Section */}
<div className="flex items-center gap-4">
<motion.div
className="h-10 w-10 relative rounded-full overflow-hidden flex-shrink-0 rink-2 rink-gray-100 dark:rink-gray-700"
whileHover={{ scale: 1.05 }}
transition={{ type: "spring", stiffness: 400, damping: 10 }}
>
<Image
src="/image.png"
fill
alt="Profile"
className="w-full h-full object-cover"
/>
</motion.div>
<motion.div className="flex-grow" variants={itemVariants}>
<h3 className="text-gray-900 dark:text-gray-50 text-sm font-semibold">
Enes Demirci
</h3>
<p className="text-xs text-gray-500 dark:text-gray-400">@enesdmc</p>
</motion.div>
<motion.button
className="text-gray-400 hover:text-gray-900 dark:hover:text-gray-50 transition-colors duration-200"
aria-label="Close"
variants={iconButtonVariants}
whileHover="hover"
whileTap="tap"
>
<X className="size-5" />
</motion.button>
</div>
{/* Input Section */}
<motion.div className="mt-5" variants={itemVariants}>
<input
type="text"
placeholder="Tell others about yourself..."
className="w-full bg-transparent text-sm text-gray-900 dark:text-gray-50 placeholder:text-gray-400 dark:placeholder:text-gray-500 outline-none transition-all duration-200"
aria-label="Bio input"
/>
</motion.div>
{/* Footer Section */}
<motion.div
variants={itemVariants}
className="flex items-center gap-4 border-t border-gray-100 dark:border-gray-800 mt-3 pt-4"
>
<div className="flex gap-4">
{[
{ Icon: Mic, label: "Voice" },
{ Icon: Video, label: "Video" },
{ Icon: Paperclip, label: "Attachment" },
{ Icon: EllipsisVertical, label: "More options" },
].map(({ Icon, label }) => (
<motion.button
key={label}
className="text-gray-400 hover:text-gray-900 dark:hover:text-gray-50 transition-colors duration-200"
aria-label={label}
variants={iconButtonVariants}
whileHover="hover"
whileTap="tap"
>
<Icon className="size-4" />
</motion.button>
))}
</div>
<motion.button
className="ml-auto bg-gray-900 dark:bg-gray-50 hover:bg-gray-800 dark:hover:bg-gray-200 text-white dark:text-gray-900 px-4 py-2 rounded-full text-xs font-medium transition-colors duration-200"
variants={publishButtonVariants}
whileHover="hover"
whileTap="tap"
>
Publish
</motion.button>
</motion.div>
</motion.div>
)
}
export default PublishPostCard
This component can be easily integrated into any Next.js project by importing the necessary packages and adding the PublishPostCard
component to the desired page. The component provides a clean and modern interface for users to publish posts with various options such as voice, video, attachments, and more. The animations and interactions enhance the user experience and make the component engaging and interactive.