# Log Live

> A live admin activity feed that streams new events, with session stats and a pause control.

A shadcn/ui block from the [@esuiss](https://suiss.app/ui?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/esuiss/log-live).

- Page, with a live preview: https://shadcn.exchange/r/esuiss/log-live
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/esuiss/log-live-light-96f23cebdbd1a967.png
- Registry item: https://suiss.app/ui/r/new-york-v4/log-live.json
- Categories: blocks, log
- Listed: 2026-10-20, source last changed 2026-10-20

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/esuiss/log-live.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@esuiss/avatar`, `@esuiss/button`, `@esuiss/sidebar`

## Files

### `components/blocks/log-live.tsx`

```tsx
"use client"

import * as React from "react"

import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarHeader,
  SidebarInset,
  SidebarMenu,
  SidebarMenuBadge,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarProvider,
  SidebarRail,
  SidebarTrigger,
  useSidebar,
} from "@/components/ui/sidebar"

type NavItem = {
  value: string
  label: string
  icon: React.ReactNode
  badge?: React.ReactNode
  group?: string
}

function NavSidebar({
  items,
  value: valueProp,
  defaultValue,
  onValueChange,
  header,
  footer,
}: {
  items: NavItem[]
  value?: string
  defaultValue?: string
  onValueChange?: (value: string) => void
  header?: React.ReactNode
  footer?: React.ReactNode
}) {
  const { isMobile, setOpenMobile } = useSidebar()
  const [uncontrolledValue, setUncontrolledValue] = React.useState(
    defaultValue ?? items[0]?.value
  )
  const value = valueProp ?? uncontrolledValue
  const groups = [...new Set(items.map((item) => item.group ?? ""))]

  return (
    <Sidebar collapsible="icon">
      {header && (
        <SidebarHeader className="group-data-[collapsible=icon]:hidden">
          {header}
        </SidebarHeader>
      )}
      <SidebarContent>
        {groups.map((group) => (
          <SidebarGroup key={group}>
            {group && <SidebarGroupLabel>{group}</SidebarGroupLabel>}
            <SidebarGroupContent>
              <SidebarMenu>
                {items
                  .filter((item) => (item.group ?? "") === group)
                  .map((item) => (
                    <SidebarMenuItem key={item.value}>
                      <SidebarMenuButton
                        isActive={item.value === value}
                        tooltip={item.label}
                        aria-current={item.value === value ? "page" : undefined}
                        onClick={() => {
                          if (valueProp === undefined) {
                            setUncontrolledValue(item.value)
                          }
                          onValueChange?.(item.value)
                          if (isMobile) setOpenMobile(false)
                        }}
                      >
                        {item.icon}
                        <span>{item.label}</span>
                      </SidebarMenuButton>
                      {item.badge !== undefined && (
                        <SidebarMenuBadge>{item.badge}</SidebarMenuBadge>
                      )}
                    </SidebarMenuItem>
                  ))}
              </SidebarMenu>
            </SidebarGroupContent>
          </SidebarGroup>
        ))}
      </SidebarContent>
      {footer && (
        <SidebarFooter className="group-data-[collapsible=icon]:hidden">
          {footer}
        </SidebarFooter>
      )}
      <SidebarRail />
    </Sidebar>
  )
}

const nav: NavItem[] = [
  {
    value: "users",
    label: "Users",
    icon: (
      <IconPlaceholder
        lucide="UsersIcon"
        tabler="IconUsers"
        hugeicons="UserGroupIcon"
        phosphor="UsersIcon"
        remixicon="RiGroupLine"
      />
    ),
  },
  {
    value: "roles",
    label: "Roles",
    icon: (
      <IconPlaceholder
        lucide="ShieldIcon"
        tabler="IconShield"
        hugeicons="Shield01Icon"
        phosphor="ShieldIcon"
        remixicon="RiShieldLine"
      />
    ),
  },
  {
    value: "log",
    label: "Activity",
    icon: (
      <IconPlaceholder
        lucide="ChartColumnIcon"
        tabler="IconChartBar"
        hugeicons="ChartColumnIcon"
        phosphor="ChartBarIcon"
        remixicon="RiBarChartLine"
      />
    ),
  },
  {
    value: "settings",
    label: "Settings",
    icon: (
      <IconPlaceholder
        lucide="SettingsIcon"
        tabler="IconSettings"
        hugeicons="Settings01Icon"
        phosphor="GearIcon"
        remixicon="RiSettingsLine"
      />
    ),
  },
]

const feed = [
  {
    actor: "Jamie Rivera",
    action: "signed in",
    detail: "Book Pro · San Francisco",
    hue: 250,
  },
  {
    actor: "System",
    action: "finished a backup",
    detail: "12.4 GB · 3 min",
    icon: (
      <IconPlaceholder
        lucide="CloudIcon"
        tabler="IconCloud"
        hugeicons="CloudIcon"
        phosphor="CloudIcon"
        remixicon="RiCloudLine"
        className="size-4"
      />
    ),
  },
  {
    actor: "Morgan Lee",
    action: "updated a product",
    detail: "Phone Air · 240 in stock",
    hue: 30,
    icon: (
      <IconPlaceholder
        lucide="TagIcon"
        tabler="IconTag"
        hugeicons="Tag01Icon"
        phosphor="TagIcon"
        remixicon="RiPriceTag3Line"
        className="size-4"
      />
    ),
  },
  {
    actor: "Riley Chen",
    action: "answered a ticket",
    detail: "#4821 Screen flickers",
    hue: 150,
    icon: (
      <IconPlaceholder
        lucide="MessageCircleIcon"
        tabler="IconMessageCircle"
        hugeicons="BubbleChatIcon"
        phosphor="ChatCircleIcon"
        remixicon="RiChat1Line"
        className="size-4"
      />
    ),
  },
  {
    actor: "System",
    action: "raised a warning",
    detail: "API latency 820 ms",
    icon: (
      <IconPlaceholder
        lucide="TriangleAlertIcon"
        tabler="IconAlertTriangle"
        hugeicons="Alert02Icon"
        phosphor="WarningIcon"
        remixicon="RiAlertLine"
        className="size-4"
      />
    ),
    warning: true,
  },
  {
    actor: "Jordan Park",
    action: "approved an order",
    detail: "W1052 · $399",
    hue: 100,
    icon: (
      <IconPlaceholder
        lucide="HandbagIcon"
        tabler="IconShoppingBag"
        hugeicons="ShoppingBag01Icon"
        phosphor="HandbagIcon"
        remixicon="RiHandbagLine"
        className="size-4"
      />
    ),
  },
]

type Entry = { id: number; time: string; event: (typeof feed)[number] }

export function LogLive() {
  const [entries, setEntries] = React.useState<Entry[]>([])
  const [running, setRunning] = React.useState(true)
  const [count, setCount] = React.useState(0)
  const next = React.useRef(0)

  React.useEffect(() => {
    if (!running) return
    const push = () => {
      const id = next.current++
      const event = feed[id % feed.length]
      if (!event) return
      const time = new Date().toLocaleTimeString("en-US", {
        hour: "numeric",
        minute: "2-digit",
      })
      setCount((current) => current + 1)
      setEntries((current) => [{ id, time, event }, ...current].slice(0, 7))
    }
    if (next.current === 0) push()
    const timer = window.setInterval(push, 2200)
    return () => window.clearInterval(timer)
  }, [running])

  const stats = [
    {
      label: "This session",
      value: `${count} ${count === 1 ? "event" : "events"}`,
    },
    { label: "Active users", value: "14" },
    { label: "Avg. response", value: "182 ms" },
  ]

  return (
    <SidebarProvider>
      <NavSidebar
        items={nav}
        defaultValue="log"
        header={
          <p className="flex items-center gap-2 px-2 pt-1 text-sm font-semibold">
            <span className="font-bold">suiss</span> Admin
          </p>
        }
      />
      <SidebarInset>
        <div className="flex flex-col gap-5 px-5 py-5.5 md:px-7">
          <div className="flex items-start gap-3">
            <SidebarTrigger className="-ms-2 mt-0.5" />
            <div className="flex flex-1 flex-col">
              <h1 className="text-3xl font-semibold tracking-tight">
                Live activity
              </h1>
              <p className="text-sm text-muted-foreground">
                {running ? "Events appear as they happen" : "Paused"}
              </p>
            </div>
            <Button
              size="sm"
              variant="secondary"
              onClick={() => setRunning(!running)}
              className="gap-1.5"
            >
              {running ? (
                <IconPlaceholder
                  lucide="PauseIcon"
                  tabler="IconPlayerPause"
                  hugeicons="PauseIcon"
                  phosphor="PauseIcon"
                  remixicon="RiPauseLine"
                  className="size-3 fill-current"
                />
              ) : (
                <IconPlaceholder
                  lucide="PlayIcon"
                  tabler="IconPlayerPlay"
                  hugeicons="PlayIcon"
                  phosphor="PlayIcon"
                  remixicon="RiPlayLine"
                  className="size-3 fill-current"
                />
              )}
              {running ? "Pause" : "Resume"}
            </Button>
          </div>
          <dl className="grid grid-cols-3 overflow-hidden rounded-xl bg-muted">
            {stats.map((stat) => (
              <div
                key={stat.label}
                className="flex min-w-0 flex-col px-3 py-3 not-first:border-s not-first:border-border md:px-4"
              >
                <dt className="truncate text-xs text-muted-foreground">
                  {stat.label}
                </dt>
                <dd className="text-xl font-semibold tabular-nums md:text-2xl">
                  {stat.value}
                </dd>
              </div>
            ))}
          </dl>
          <div className="-mb-2.5 flex items-center gap-2 px-1">
            <h2 className="flex-1 text-sm font-semibold">Recent events</h2>
            {running && (
              <span className="flex items-center gap-1.5 text-xs text-muted-foreground">
                <span className="size-1.75 animate-pulse rounded-full bg-green-500" />
                Live
              </span>
            )}
          </div>
          <ul
            aria-live="polite"
            aria-relevant="additions"
            className="overflow-hidden rounded-2xl bg-muted"
          >
            {entries.map(({ id, time, event }) => (
              <li
                key={id}
                className="relative flex min-h-11 items-center gap-3 px-4 py-2 transition-[opacity,translate] duration-700 ease-[cubic-bezier(0.32,0.72,0,1)] not-first:before:absolute not-first:before:inset-e-0 not-first:before:inset-s-14 not-first:before:top-0 not-first:before:h-px not-first:before:bg-border starting:-translate-y-2.5 starting:opacity-0 motion-reduce:transition-none"
              >
                {event.hue ? (
                  <Avatar className="size-7">
                    <AvatarFallback
                      style={{
                        background: `linear-gradient(160deg, oklch(0.78 0.1 ${event.hue}), oklch(0.6 0.14 ${event.hue + 30}))`,
                      }}
                      className="text-xs text-white"
                    >
                      {event.actor
                        .split(" ")
                        .map((part) => part[0])
                        .join("")}
                    </AvatarFallback>
                  </Avatar>
                ) : (
                  <span
                    data-warning={event.warning ? "" : undefined}
                    className="flex size-7 shrink-0 items-center justify-center rounded-[7px] bg-zinc-500 text-white data-warning:bg-orange-500"
                  >
                    {event.icon}
                  </span>
                )}
                <span className="flex min-w-0 flex-1 flex-col">
                  <span className="truncate text-sm">
                    <strong className="font-semibold">{event.actor}</strong>{" "}
                    {event.action}
                  </span>
                  <span className="truncate text-xs text-muted-foreground">
                    {event.detail}
                  </span>
                </span>
                <span className="text-sm text-muted-foreground tabular-nums">
                  {time}
                </span>
              </li>
            ))}
          </ul>
        </div>
      </SidebarInset>
    </SidebarProvider>
  )
}
```
