# Activity Feed Page

Activity feed page with shell, filters, composer, and notifications rail.

## Installation

```bash
npx shadcn@latest add https://ui.uptoolkit.com/r/activity-feed-page.json
```

[Registry JSON](https://ui.uptoolkit.com/r/activity-feed-page.json)

## Preview

```tsx
import Page from "app/activity/page";

export function Preview() {
  return <Page />;
}
```


## Source

### page.tsx

```tsx
import { ActivityFeedPageContent } from "@/components/activity-feed-page-content";

/**
 * Activity feed page.
 *
 * Composes {@link ActivityFeedShell} around a full {@link ActivityFeed} with
 * filters, date grouping, and a notifications rail. Swap the sample collection
 * for a live `outbox` or `inbox` fetch here and pass the results into
 * `ActivityFeedPageContent`.
 */
export default function Page() {
  return <ActivityFeedPageContent />;
}
```


### components/activity-feed-page-content.tsx

```tsx
"use client";

import {
  IconBookmark,
  IconCalendarEvent,
  IconHome,
  IconUsersGroup,
  IconWorld,
} from "@tabler/icons-react";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

import { ActivityFeedShell } from "@/components/activity-feed-shell";
import { ActivityFeed } from "@/components/activity-feed";
import { ActorGrid } from "@/components/actor-grid";
import { NotificationsPanel } from "@/components/notifications-panel";
import { JsonLd } from "@/components/json-ld";
import { sampleActivityCollection } from "@/lib/activity-entries";
import { toPersonJsonLd } from "@/lib/schema-org";
import {
  SAMPLE_NOW,
  sampleCounts,
  sampleFollowers,
  sampleInbox,
  sampleSuggestions,
  sampleViewer,
} from "@/lib/social-sample-data";

const shortcuts = [
  { label: "Home", icon: IconHome, href: "/activity", active: true },
  { label: "Friends", icon: IconUsersGroup, href: "/friends" },
  { label: "Explore", icon: IconWorld, href: "/explore" },
  { label: "Saved", icon: IconBookmark, href: "/saved" },
  { label: "Events", icon: IconCalendarEvent, href: "/events" },
];

/**
 * Client half of the activity feed page.
 *
 * Holds navigation icons and interactive blocks so the server `page.tsx` can
 * stay a thin wrapper around data fetching.
 */
export function ActivityFeedPageContent() {
  const viewerJsonLd = toPersonJsonLd(sampleViewer, { counts: sampleCounts.viewer });

  return (
    <ActivityFeedShell
      viewer={sampleViewer}
      brand={{ name: "Activity", href: "/activity" }}
      nav={shortcuts}
      notificationsCount={sampleInbox.totalItems ?? 0}
      sidebar={
        <ActorGrid
          actors={sampleFollowers.slice(0, 4)}
          heading="Contacts"
          variant="row"
          columns={1}
          includeJsonLd={false}
        />
      }
      rail={
        <>
          <JsonLd data={viewerJsonLd} />

          <NotificationsPanel
            collection={sampleInbox}
            viewer={sampleViewer}
            maxHeight={320}
            now={SAMPLE_NOW}
            className="max-w-none"
          />

          <Card className="gap-3 py-4">
            <CardHeader>
              <CardTitle className="text-base">People you may know</CardTitle>
            </CardHeader>
            <CardContent>
              <ActorGrid
                actors={sampleSuggestions}
                heading="Suggestions"
                variant="row"
                columns={1}
                includeJsonLd={false}
                className="gap-2 [&>div:first-child]:hidden"
              />
            </CardContent>
          </Card>
        </>
      }
    >
      <ActivityFeed
        viewer={sampleViewer}
        collection={sampleActivityCollection}
        heading="Your activity"
        variant="full"
        showComments
        now={SAMPLE_NOW}
      />
    </ActivityFeedShell>
  );
}
```



## Usage

A complete activity feed page: shell, full activity stream with filters and date
grouping, contacts in the sidebar, and notifications plus suggestions in the
rail.

```bash
npx shadcn@latest add @uptoolkit/activity-feed-page
```

Installs to `app/activity/page.tsx` along with every block, component, and
helper it uses.

```tsx
import { parseHandle, buildWebFingerUrl } from "@/lib/activitypub";

const [outbox, inbox, contacts, suggestions] = await Promise.all([
  fetchOutbox(viewer),
  fetchInbox(viewer),
  fetchFollowing(viewer),
  fetchSuggestions(viewer),
]);

// ...pass each into ActivityFeedShell, ActivityFeed, and ActorGrid
```

The page emits a Schema.org `Person` node for the signed-in actor, and the feed
inside emits its own `CollectionPage`.

For a plain post timeline without the full activity vocabulary, set
`variant="timeline"` on [`activity-feed`](/blocks/activity-feed). For a profile wall with visitor
posts, see [`wall-page`](/pages/wall-page).

