Education
Announcement Card - Communications Dashboard
Display school announcements and notices efficiently. Manage communications with students, parents, and staff.
Announcement Card
The Announcement Card displays important school board announcements and notices with timestamps and visual indicators.
Preview
Installation
npx shadcn@latest add https://vectormotion.vercel.app/registry/announcement-card.jsonAnnouncement Card
'use client'import React from 'react';import { Megaphone, MessageCircle } from 'lucide-react';import { motion } from 'motion/react';import { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge";function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs));}interface AnnouncementCardProps { className?: string; title?: string; subtitle?: string; announcementTitle?: string; announcementContent?: string; timeAgo?: string; commentCount?: string; hasUnread?: boolean;}const DEFAULT_TITLE = "Notices";const DEFAULT_SUBTITLE = "School Board";const DEFAULT_ANNOUNCEMENT_TITLE = "Staff Development Day";const DEFAULT_ANNOUNCEMENT_CONTENT = "School will be closed this Friday for staff training. Regular classes resume Monday.";const DEFAULT_TIME_AGO = "2 hours ago";const DEFAULT_COMMENT_COUNT = "5 comments";export const AnnouncementCard: React.FC<AnnouncementCardProps> = ({ className = "", title = DEFAULT_TITLE, subtitle = DEFAULT_SUBTITLE, announcementTitle = DEFAULT_ANNOUNCEMENT_TITLE, announcementContent = DEFAULT_ANNOUNCEMENT_CONTENT, timeAgo = DEFAULT_TIME_AGO, commentCount = DEFAULT_COMMENT_COUNT, hasUnread = true,}) => { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 0.1 }} className={cn( "relative overflow-hidden rounded-2xl border border-border bg-card text-card-foreground shadow-sm transition-all hover:border-orange-300 dark:hover:border-orange-700 hover:shadow-md flex flex-col h-full", className )} > <div className="absolute top-0 right-0 p-4 opacity-5 pointer-events-none"> <Megaphone className="w-24 h-24 text-orange-500 transform rotate-12" /> </div> <div className="p-5 flex flex-col h-full relative z-10"> <div className="mb-4 flex items-start justify-between"> <div> <h3 className="font-bold text-lg text-foreground"> {title} </h3> <p className="text-sm text-muted-foreground font-medium"> {subtitle} </p> </div> <div className="relative"> <div className="rounded-xl bg-orange-500/10 p-2.5 text-orange-500 dark:text-orange-400 flex items-center justify-center ring-1 ring-orange-100 dark:ring-orange-800"> <Megaphone className="h-5 w-5" /> </div> {hasUnread && ( <motion.span initial={{ scale: 0 }} animate={{ scale: 1 }} transition={{ delay: 1, type: "spring" }} className="absolute -top-1 -right-1 h-3 w-3 bg-red-500 rounded-full border-2 border-white dark:border-zinc-900" /> )} </div> </div> <div className="flex-1 flex flex-col justify-center space-y-3"> <motion.div initial={{ x: -20, opacity: 0 }} animate={{ x: 0, opacity: 1 }} transition={{ delay: 0.2 }} className="p-3 bg-orange-50 dark:bg-orange-900/10 rounded-lg border border-orange-100 dark:border-orange-900/20 relative" > <div className="absolute -left-1 top-4 w-2 h-2 bg-orange-400 rounded-full" /> <h4 className="text-sm font-semibold text-zinc-800 dark:text-zinc-200 mb-1">{announcementTitle}</h4> <p className="text-xs text-zinc-600 dark:text-muted-foreground leading-relaxed"> {announcementContent} </p> <div className="flex items-center gap-2 mt-2"> <span className="text-[10px] text-zinc-400 font-medium">{timeAgo}</span> <div className="flex items-center gap-1 text-[10px] text-orange-500 font-medium"> <MessageCircle className="w-3 h-3" /> <span>{commentCount}</span> </div> </div> </motion.div> </div> </div> </motion.div> );};Usage
This component provides a visually appealing way to display school announcements, keeping students, parents, and staff informed of important updates.
Prop
Type