Omarchy Notification Center

block

A dismissable notification history mirroring omarchy-shell notifications.

bunx --bun shadcn@latest add yamz8/omarchy-shadcn-registry/omarchy-notification-center

Preview

Notifications
3 unread
  • Systemnow

    Theme switched to Tokyo Night.

  • Updates4m

    12 packages ready to upgrade.

  • Backup1h

    Snapshot failed — target unreachable.

Dismiss all

Dependencies

npm
lucide-react
registry
button, card, empty, yamz8/omarchy-shadcn-registry/omarchy-keycap, yamz8/omarchy-shadcn-registry/omarchy-status

Source

registry/blocks/omarchy-notification-center.tsx
"use client"

import * as React from "react"
import { XIcon } from "lucide-react"

import { Button } from "@/components/ui/button"
import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import {
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyTitle,
} from "@/components/ui/empty"
import { OmarchyShortcut } from "@/components/ui/omarchy-keycap"
import { OmarchyStatus } from "@/components/ui/omarchy-status"

type OmarchyNotification = {
  id: string
  app: string
  body: string
  time: string
  status: React.ComponentProps<typeof OmarchyStatus>["status"]
}

const initialNotifications: readonly OmarchyNotification[] = [
  {
    id: "1",
    app: "System",
    body: "Theme switched to Tokyo Night.",
    time: "now",
    status: "active",
  },
  {
    id: "2",
    app: "Updates",
    body: "12 packages ready to upgrade.",
    time: "4m",
    status: "idle",
  },
  {
    id: "3",
    app: "Backup",
    body: "Snapshot failed — target unreachable.",
    time: "1h",
    status: "error",
  },
]

/** Mirrors `omarchy-shell notifications`: a dismissable notification history. */
export function OmarchyNotificationCenter() {
  const [notifications, setNotifications] = React.useState(initialNotifications)

  return (
    <Card className="w-full max-w-md">
      <CardHeader>
        <CardTitle>Notifications</CardTitle>
        <CardDescription>
          {notifications.length === 0
            ? "Nothing waiting."
            : `${notifications.length} unread`}
        </CardDescription>
        {notifications.length > 0 ? (
          <CardAction>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => setNotifications([])}
            >
              Dismiss all
            </Button>
          </CardAction>
        ) : null}
      </CardHeader>
      <CardContent>
        {notifications.length === 0 ? (
          <Empty className="py-6">
            <EmptyHeader>
              <EmptyTitle>Inbox clear</EmptyTitle>
              <EmptyDescription>
                New notifications appear here as they arrive.
              </EmptyDescription>
            </EmptyHeader>
          </Empty>
        ) : (
          <ul className="flex flex-col gap-2">
            {notifications.map((notification) => (
              <li
                key={notification.id}
                className="flex items-start gap-3 rounded-md border border-border p-2.5"
              >
                <div className="flex min-w-0 flex-col gap-1.5">
                  <div className="flex items-center gap-2">
                    <OmarchyStatus status={notification.status}>
                      {notification.app}
                    </OmarchyStatus>
                    <span className="font-mono text-[0.6875rem] text-muted-foreground">
                      {notification.time}
                    </span>
                  </div>
                  <p className="text-sm leading-relaxed">{notification.body}</p>
                </div>
                <Button
                  variant="ghost"
                  size="icon-sm"
                  className="ml-auto"
                  onClick={() =>
                    setNotifications((current) =>
                      current.filter((item) => item.id !== notification.id)
                    )
                  }
                >
                  <XIcon />
                  <span className="sr-only">
                    Dismiss notification from {notification.app}
                  </span>
                </Button>
              </li>
            ))}
          </ul>
        )}
      </CardContent>
      <CardFooter className="justify-between gap-4">
        <span className="text-xs text-muted-foreground">Dismiss all</span>
        <OmarchyShortcut keys={["Super", "Shift", ","]} />
      </CardFooter>
    </Card>
  )
}