nili/ui
All components

ActivityFeed

Overview
24 exports3 variant axes36 props4 files
import { ActivityFeed, ActivityFeedFile, ActivityFeedFooter, ActivityFeedHeader, ActivityFeedItemType, ActivityFeedKey } from '@nili/ui';

This is the library’s own overview page, rendered live. Switch the language or the theme in the header and it follows.

Item types

Four kinds of row: plain text, a row with actions, a row carrying a file, and a row quoting a message. The type decides which slot is drawn, and the slots are props rather than children so a row cannot be assembled wrongly.

  • AL
    Ada Lovelace commented
    Design system

    This looks good to me — shipping it.

  • GH
    Grace Hopper wants to join the workspace
  • KJ
    Katherine Johnson shared a file
  • RP
    Radia Perlman replied
    Can we move the review to Thursday morning?
import { ActivityFeedItem, Avatar, Button } from "@nili/ui"

export function Example() {
  return (
    <>
      <ActivityFeedItem
        type="basic"
        avatar={<Avatar size="sm" name="Ada Lovelace" tone="blue" />}
        title="Ada Lovelace commented"
        timestamp="8 min ago"
        subject="Design system"
        description="This looks good to me — shipping it."
      />

      <ActivityFeedItem
        type="button"
        avatar={<Avatar size="sm" name="Grace Hopper" tone="purple" />}
        title="Grace Hopper wants to join"
        timestamp="1 h ago"
        actions={
          <>
            <Button size="xs">Accept</Button>
            <Button size="xs" appearance="stroke">Decline</Button>
          </>
        }
      />

      <ActivityFeedItem
        type="file"
        title="Katherine shared a file"
        file={{ name: "annual-report.pdf", size: "4mb", href: "#" }}
      />

      <ActivityFeedItem
        type="message"
        title="Radia replied"
        message="Can we move the review to Thursday?"
      />
    </>
  )
}

Unread and selectable rows

onSelect turns the title into a real button that stretches over the card — so the row is clickable while the actions and the menu inside it stay separate, focusable buttons of their own. A row with an onClick on the wrapper would swallow all of them.

  • AL
    New
    Design system
  • BL
import { ActivityFeedItem } from "@nili/ui"

export function Example() {
  return (
    <>
      <ActivityFeedItem
        unread
        onSelect={() => open(notification)}
        title="Ada Lovelace mentioned you"
        timestamp="8 min ago"
        badge={<Badge size="small" color="blue" appearance="lighter">New</Badge>}
      />
      <ActivityFeedItem
        onSelect={() => open(notification)}
        title="Already read"
        timestamp="2 days ago"
      />
    </>
  )
}

The whole panel

Header, tab row and footer are all slots on ActivityFeed. The tabs are plain buttons rather than a Tabs instance — they filter one list in place instead of swapping panels, and calling that a tablist would lie to a screen reader.

tab: all

Notifications

  • AL
    Design system

    Can you take a look at the new Badge colours?

  • GH
  • KJ
import {
  ActivityFeed, ActivityFeedItem, ActivityFeedTab,
  ActivityFeedTabSeparator, ActivityFeedFooter, LinkButton,
} from "@nili/ui"

export function Example() {
  const [tab, setTab] = useState("all")

  return (
    <ActivityFeed
      label="Notifications"
      title="Notifications"
      headerAction={<LinkButton color="primary" size="sm">Mark all as read</LinkButton>}
      tabs={
        <>
          <ActivityFeedTab selected={tab === "all"} onClick={() => setTab("all")}>
            All
          </ActivityFeedTab>
          <ActivityFeedTab
            selected={tab === "unread"}
            onClick={() => setTab("unread")}
            count={3}
          >
            Unread
          </ActivityFeedTab>
          <ActivityFeedTabSeparator />
          <ActivityFeedTab selected={tab === "mentions"} onClick={() => setTab("mentions")}>
            Mentions
          </ActivityFeedTab>
        </>
      }
      footer={
        <ActivityFeedFooter
          hint={<><ActivityFeedKey>↑</ActivityFeedKey><ActivityFeedKey>↓</ActivityFeedKey> to navigate</>}
          action={<LinkButton href="#" size="sm">See all activity</LinkButton>}
        />
      }
    >
      …
    </ActivityFeed>
  )
}