bottega

cards

Notification Alert Card

A compact notification/alert surface card: a `--primary`-tinted circle icon (megaphone), a bold heading, muted body text, and two full-width action links (primary CTA + dismiss). The icon circle background is a 15% primary tint over `--background`, so it reads on both light and dark without hardcoded colors. Action links have `:focus-visible` rings and subtle hover transitions. Server-renderable — no JS required. Port of uiverse.io/Yaya12085/terrible-otter-19 (MIT).

Ported from Yaya12085 (MIT)

New message!

Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam ea quo unde vel adipisci blanditiis voluptates eum.


Install

1. Register the namespace (once per project):

json
// components.json — register the @bottega namespace once
{
  "registries": {
    "@bottega": { "url": "https://bottega.ariacode.ca/r/{name}.json" }
  }
}

2. Add the component:

bash
npx shadcn add @bottega/notification-alert-card

Usage

Usagetsx
<NotificationAlertCard />

Props

PropTypeDefaultDescription
titlestringNew message!Card heading shown beside the icon. Default: "New message!".
messagestringLorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam ea quo unde vel adipisci blanditiis voluptates eum.Body copy below the heading.
primaryLabelstringTake a LookLabel for the primary CTA link.
primaryHrefstring#href for the primary CTA link.
secondaryLabelstringMark as ReadLabel for the secondary dismiss link.
secondaryHrefstring#href for the secondary dismiss link.
classNamestringAdditional class names merged onto the root element.

Source

notification-alert-card.tsxtsx
import type React from "react";
import styles from "./notification-alert-card.module.css";

export type NotificationAlertCardProps = {
  /** Card heading shown beside the icon. Default: "New message!". */
  title?: string;
  /** Body copy below the heading. */
  message?: string;
  /** Label for the primary CTA link. */
  primaryLabel?: string;
  /** href for the primary CTA link. */
  primaryHref?: string;
  /** Label for the secondary dismiss link. */
  secondaryLabel?: string;
  /** href for the secondary dismiss link. */
  secondaryHref?: string;
  /** Additional class names merged onto the root element. */
  className?: string;
};

/** Megaphone icon — always aria-hidden; fill inherits from parent color. */
function MegaphoneIcon() {
  return (
    <svg
      aria-hidden="true"
      fill="currentColor"
      viewBox="0 0 20 20"
      xmlns="http://www.w3.org/2000/svg"
      className={styles.iconSvg}
    >
      <path
        clipRule="evenodd"
        d="M18 3a1 1 0 00-1.447-.894L8.763 6H5a3 3 0 000 6h.28l1.771 5.316A1 1 0 008 18h1a1 1 0 001-1v-4.382l6.553 3.276A1 1 0 0018 15V3z"
        fillRule="evenodd"
      />
    </svg>
  );
}

/**
 * NotificationAlertCard — a surface card with a `--primary`-tinted icon circle
 * (megaphone), a heading, body text, and two action links (primary CTA +
 * dismiss). All color comes from design tokens so it themes correctly on both
 * light and dark. Server-renderable — no hooks required.
 *
 * Port of https://uiverse.io/Yaya12085/terrible-otter-19 (MIT).
 */
export function NotificationAlertCard({
  title = "New message!",
  message =
    "Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam ea quo unde vel adipisci blanditiis voluptates eum.",
  primaryLabel = "Take a Look",
  primaryHref = "#",
  secondaryLabel = "Mark as Read",
  secondaryHref = "#",
  className = "",
}: NotificationAlertCardProps) {
  const rootClass = [styles.card, className].filter(Boolean).join(" ");

  return (
    <div className={rootClass} role="article">
      <div className={styles.header}>
        {/* Icon circle — decorative container, aria-hidden; color=--primary so SVG currentColor picks it up */}
        <span className={styles.iconCircle} aria-hidden="true">
          <MegaphoneIcon />
        </span>
        <p className={styles.alert}>{title}</p>
      </div>

      <p className={styles.message}>{message}</p>

      <div className={styles.actions}>
        <a className={styles.read} href={primaryHref}>
          {primaryLabel}
        </a>
        <a className={styles.markAsRead} href={secondaryHref}>
          {secondaryLabel}
        </a>
      </div>
    </div>
  );
}

Dependencies

  • @bottega/tokens