Dashboard
The admin home is /admin/home. It shows a header and a grid of widgets.
The header has the date, the title "Dashboard", and a create button. With one content type, the button reads "New <label>". With several types, it is a Create menu.
Core widgets
| Widget | Order | Columns | Shows |
|---|---|---|---|
content-overview | 0 | 3 | One tile for each content type |
content-activity | 10 | 2 | Items created each week, for the last 12 weeks |
quick-actions | 20 | 1 | Create commands and a few admin destinations |
content-overview and content-activity are off while no content type is registered.
Content tiles
Each tile shows the plural label, an icon, and the total. When activity data exists, it adds "+N this week". For a type with a status workflow, it adds a meter of the published share and the text "N published · M drafts". The text says the same numbers, so the share never depends on color alone.
A tile links to the list of the type.
Activity chart
The chart shows an area for one content type and lines for several. The series colors come from the admin theme.
A hidden table has the same numbers. The chart shows a skeleton while it loads, an error alert with Try again, "Activity is not available" when no adapter can count by creation date, and an empty state when nothing was created.
The data comes from this route:
GET /api/_pluto/content-activity/<type>?weeks=12
weeks is from 1 to 52. The answer is { supported, interval: 'week', points: [{ start, count }] }, oldest first. Weeks start on Monday, in UTC.
The route calls the optional countCreated(ctx, { from, to }) of the adapter once for each week. It returns supported: false when the adapter has no such method, or when the method returns null.
Quick actions
The widget shows the same Create and Go to commands as the command palette, without Home.
Add a widget
const RecentPostsWidget = defineAsyncComponent(() => import('../components/RecentPostsWidget.vue'))
export default defineNuxtPlugin(() => {
definePlutoExtension({
id: 'supabase-blog',
dashboardWidgets: [
{ id: 'recent-posts', component: RecentPostsWidget, colSpan: 2 }
]
})
})
A widget with the default order (100) goes below the core widgets. The grid has 3 columns on the lg breakpoint.
Each widget has its own <Suspense>. The grid paints at once. A card skeleton shows until the widget code loads. The skeleton height depends on colSpan.
Translation
All dashboard text is translated. Numbers and dates use n() and d(), so they follow the admin language.