enesdmc
➜ All Components

Publish Post Card

Oct 22
·
2024
Profile

Enes Demirci

@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.

Installation

To install the Publish Post Card component run:

Install
bun add framer-motion
bun add lucide-react
Framer Motion

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.

Usage

App.tsx
"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.