Event.tsx

An animated announcement banner component in Plainform that displays promotional events with shiny text effects and border beams

The Event component displays promotional announcements or events with eye-catching animations. It fetches event data from the database and renders an animated banner with border beam effects.

Usage

Basic Implementation

@/app/(base)/page.tsx
import { Event } from '@/components/Event';

export default function HomePage() {
  return (
    <main>
      <Event />
    </main>
  );
}

In Hero Section

@/components/Hero.tsx
import { Event } from '@/components/Event';

export function Hero() {
  return (
    <section className="flex flex-col items-center gap-4">
      <Event />
      <h1>Welcome to Our Product</h1>
      <p>Your tagline here</p>
    </section>
  );
}

Features

  • Database-Driven: Fetches event data from Prisma database
  • Mock Fallback: Displays mock event from locale when no database event exists
  • Dynamic Icons: Supports custom icons via SvgFinder or defaults to ✨
  • Type-Based Links: Opens product events in new tab, others in same tab
  • Animated Text: Shiny text effect with gradient animation
  • Border Beams: Dual animated border beams with different colors
  • Conditional Rendering: Only displays when event exists
  • Responsive: Adapts to mobile and desktop layouts

Implementation Details

Data Fetching

The component uses the getEvent function to fetch data:

@/lib/events/getEvent.ts
export async function getEvent() {
  // Fetches latest event from database
  // Returns { event: { text, slug, type, icon, timestamp } }
}

Returns:

  • event.text - Event announcement text
  • event.slug - URL slug for event link
  • event.type - Event type: 'post', 'coupon', or 'product'
  • event.icon - Optional icon name
  • event.timestamp - Creation timestamp

Mock Event Fallback

If no database event exists, displays mock event from locale:

Mock Fallback
const data = await getEvent();
const mockEvent = locale?.homePage?.mockEvent;

// Use real event if available, otherwise use mock event
const event = data?.event || mockEvent;

Mock event structure in locales/en.json:

{
  "homePage": {
    "mockEvent": {
      "text": "Your event announcement goes here",
      "slug": "/#buy",
      "type": "coupon",
      "icon": null
    }
  }
}

Conditional Rendering

The component returns null if no event exists:

Conditional Rendering
if (!event) {
  return null;
}

Different event types open in different targets:

Target Logic
const target: Record<string, '_blank' | ''> = {
  product: '_blank',  // Opens in new tab
  post: '',           // Opens in same tab
  coupon: '',         // Opens in same tab
};

<Link
  href={event?.slug}
  target={target[event?.type] || ''}
>

Icon Rendering

Displays custom icon or default sparkle:

Icon Logic
{event?.icon ? (
  <SvgFinder icon={event?.icon} size={14} />
) : (
  <span>✨</span>
)}

Animation Effects

The component uses two animated effects:

  1. AnimatedShinyText: Gradient text animation
  2. BorderBeam: Dual animated border beams
Animation Structure
<Link href={event?.slug} target={target[event?.type] || ''}>
  <AnimatedShinyText className="flex items-center gap-4 justify-center">
    <div className="flex gap-2 items-center">
      {event?.icon ? (
        <SvgFinder icon={event?.icon} size={14} />
      ) : (
        <span>✨</span>
      )}
      <span className="line-clamp-1">{event?.text}</span>
    </div>
    <MoveRight size={14} />
  </AnimatedShinyText>

  {/* First border beam - indigo */}
  <BorderBeam
    duration={6}
    size={1000}
    initialOffset={1400}
    borderWidth={0.5}
    className="from-transparent via-indigo-500 to-transparent"
  />

  {/* Second border beam - pink */}
  <BorderBeam
    duration={6}
    delay={3}
    size={1000}
    initialOffset={1400}
    borderWidth={0.5}
    className="from-transparent via-pink-400 to-transparent"
  />
</Link>

Customization

Changing Border Colors

Modify the gradient colors in BorderBeam:

Custom Colors
<BorderBeam
  duration={6}
  size={1000}
  initialOffset={1400}
  borderWidth={0.5}
  className="from-transparent via-blue-500 to-transparent"
/>
<BorderBeam
  duration={6}
  delay={3}
  size={1000}
  initialOffset={1400}
  borderWidth={0.5}
  className="from-transparent via-green-400 to-transparent"
/>

Adjusting Animation Speed

Change the duration prop:

Faster Animation
<BorderBeam
  duration={3}
  size={1000}
  initialOffset={1400}
  borderWidth={0.5}
  className="from-transparent via-indigo-500 to-transparent"
/>

Border Width

Adjust the border thickness:

Thicker Border
<BorderBeam
  duration={6}
  size={1000}
  initialOffset={1400}
  borderWidth={1.5}
  className="from-transparent via-indigo-500 to-transparent"
/>

Modify the target behavior:

Custom Targets
const target: Record<string, '_blank' | ''> = {
  product: '_blank',
  post: '_blank',    // Open posts in new tab
  coupon: '',
};

Database Schema

The event data comes from the Prisma database:

@/prisma/schema.prisma
model Event {
  id        String  @id @default(cuid())
  type      String  // 'post', 'coupon', or 'product'
  slug      String  // URL to link to
  text      String  // Display text
  icon      String? // Optional icon name
  timestamp BigInt  // Creation timestamp
  
  @@index([type])
}

Creating Events

To add a new event, use the Events API:

Create event via Postman
POST http://localhost:3000/api/events
Content-Type: application/json
Authorization: Bearer your_event_api_secret

{
  "text": "🎉 New feature launched! Check it out",
  "type": "post",
  "slug": "/blog/new-feature-launch",
  "icon": "Rocket"
}

The component will automatically display the latest event.

For more details, see Events Documentation.

How is this guide ?

Last updated on

On this page