whatsnew-embed
v1.0.2
Published
Reusable React component to embed 'What's New' updates via API
Maintainers
Readme
📢 whatsnew-embed
Easily manage and showcase "What's New" updates in your application.whatsnew-embed lets you display release notes, feature announcements, and updates beautifully, with ready-to-use components for featured embeds and update cards.
✨ Features
- 🎨 Prebuilt, responsive UI components for update listings
- ⚡ Easy integration into any React app
- 🛠 Customizable styles via
classesprop - 🔄 Supports dynamic fetching from your backend
- 📅 Automatically sorts updates by date
- 🖱 Clickable cards to view detailed updates
📦 Installation
npm install whatsnew-embed
Usage Example
import { useEffect, useState, useMemo } from "react"
import { Sparkles } from "lucide-react"
import { WhatsNewCard, WhatsNewEmbed } from "whatsnew-embed"
import type { WhatsNewItem } from "../types"
const API_URL = (username: string) => `http://localhost:8000/api/v1/public/whatsnew/${username}`
export default function WhatsNewApp() {
const [entries, setEntries] = useState<WhatsNewItem[]>([])
const [selected, setSelected] = useState<WhatsNewItem | null>(null)
useEffect(() => {
fetch(API_URL(username))
.then((res) => res.json())
.then((data) => {
const sorted = data.message.entries
.sort((a: any, b: any) => new Date(b.date).getTime() - new Date(a.date).getTime())
.map((entry: any) => ({ ...entry, id: entry._id }))
setEntries(sorted)
})
.catch((err) => {
console.error("Failed to fetch What's New entries:", err)
})
}, [username])
const featured = selected ?? entries[0]
const others = useMemo(() => entries.filter((e) => e.id !== featured?.id), [entries, featured])
return (
<div className="max-w-6xl mx-auto py-12 px-4">
{/* Header */}
<div className="text-center mb-12">
<div className="flex justify-center items-center gap-2 text-blue-600">
<Sparkles className="h-6 w-6" />
<h1 className="text-4xl font-bold">What's New</h1>
</div>
<p className="text-muted-foreground mt-2">Explore the latest updates and features.</p>
</div>
{/* Featured Update */}
{featured && (
<div className="mb-12">
<WhatsNewEmbed
key={featured.id}
update={featured}
showBackButton={!!selected}
onBack={() => setSelected(null)}
classes={{
wrapper: "bg-gradient-to-br from-white to-gray-100 shadow-2xl p-10",
content: "prose prose-indigo",
}}
/>
</div>
)}
{/* Other Updates */}
{others.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{others.map((entry) => (
<WhatsNewCard key={entry.id} update={entry} onClick={() => setSelected(entry)} />
))}
</div>
)}
</div>
)
}
WhatsNewEmbed Props
| Prop | Type | Description |
| ---------------- | ---------------------------------------- | ------------------------------------ |
| `update` | `WhatsNewItem` | Update object to display |
| `showBackButton` | `boolean` | Whether to show a back button |
| `onBack` | `() => void` | Callback when back button is clicked |
| `classes` | `{ wrapper?: string; content?: string }` | Custom CSS classes |
WhatsNewCard Props
| Prop | Type | Description |
| --------- | -------------- | ---------------------------------- |
| `update` | `WhatsNewItem` | Update object for card view |
| `onClick` | `() => void` | Click handler for selecting update |
🎯 Customization
You can fully style the embed and cards using Tailwind CSS (or your own CSS classes) via the classes prop.