Saltar al contenido
ssntl/ui

Announcement

Una píldora de novedades con una insignia interna que se anida en su curva.

Instalación

$ pnpm dlx shadcn@latest add @ssntl/announcement

Uso

tsx
import { Announcement, AnnouncementTag } from "@/components/ui/announcement"

<Announcement href="/novedades/tarjetas-de-regalo">
  <AnnouncementTag>Nuevo</AnnouncementTag>
  Llegaron las tarjetas de regalo
</Announcement>

Reglas

Lo que este componente espera de ti, tal como se instala en components/ui/announcement.md junto al código. El archivo completo agrega cuándo usarlo, teclado, los fundamentos de UI que aplica y cada regla compartida (en inglés).

components/ui/announcement.md
## Reglas de Announcement

- **Aviso + insignia interna.** Una insignia en píldora a 4px dentro de una píldora, así su radio es el exterior menos el padding.
- La insignia lleva una palabra (Nuevo, Beta) y el texto del enlace dice qué hay de nuevo.
- Toda la píldora es un solo objetivo; la flecha se mueve 2px al pasar el cursor y queda quieta con movimiento reducido.
Abrir el archivo de reglas completo (se abre en otra pestaña)

Código

components/ui/announcement.tsx
import * as React from "react"
import { ChevronRight } from "lucide-react"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

// A pill that links to news ("New · Gift cards are here"). Nested corners:
// the badge is a pill inset 4px inside a pill, so its radius is the outer
// one minus the padding, by construction. The badge carries a word, and the
// whole pill is one 40px target.
function Announcement({
  asChild = false,
  className,
  children,
  ...props
}: React.ComponentProps<"a"> & { asChild?: boolean }) {
  const Comp = asChild ? Slot.Root : "a"
  return (
    <Comp
      data-slot="announcement"
      className={cn(
        "group inline-flex min-h-10 max-w-full items-center gap-3 rounded-full bg-secondary p-1 pe-3 text-caption text-foreground",
        "transition-[background-color] duration-(--duration-fast) ease-out hover:bg-neutral-200 dark:hover:bg-neutral-600",
        "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
        className
      )}
      {...props}
    >
      <Slot.Slottable>{children}</Slot.Slottable>
      <ChevronRight
        aria-hidden
        strokeWidth={1.6}
        className="size-4 shrink-0 opacity-80 transition-[translate] duration-(--duration-fast) ease-out group-hover:translate-x-0.5 motion-reduce:transition-none rtl:rotate-180"
      />
    </Comp>
  )
}

/** The inset badge: a word, on the card surface. */
function AnnouncementTag({
  className,
  ...props
}: React.ComponentProps<"span">) {
  return (
    <span
      data-slot="announcement-tag"
      className={cn(
        "inline-flex h-8 shrink-0 items-center rounded-full bg-card px-3 font-medium elevation-1",
        className
      )}
      {...props}
    />
  )
}

export { Announcement, AnnouncementTag }