Snapshot, module
Install
npx shadcn add @klarhimmel/snapshot-moduleUsage
import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import SnapshotModule from '@/components/klarhimmel/blocks/snapshot-module';
export default function Section() {
return (
<Theme theme="brand">
<BlockSurface>
<SnapshotModule props={{
"title": "Competitors",
"status": "ready",
"note": "",
"output": {
"headline": "Three firms compete with you for the same searches",
"summary": "Two of them publish fixed prices and answer within a day. You do neither on the page people land on.",
"items": [
{
"id": "sug_1",
"kind": "suggestion",
"title": "Put your fixed monthly price on the start page",
"detail": "Both nearby firms show theirs above the fold.",
"priority": "1",
"effort": "small",
"impact": "More people reach the contact form.",
"links": [
{
"label": "Their pricing page",
"url": "https://rival.example/pricing"
}
],
"sources": [
"src_1",
"src_2"
]
},
{
"id": "fin_1",
"kind": "finding",
"title": "One competitor answers questions in a short FAQ",
"detail": "It is the page an AI assistant quotes most.",
"links": [
{
"label": "Their FAQ",
"url": "https://rival.example/faq"
}
],
"sources": [
"src_2"
]
}
],
"sources": [
{
"id": "src_1",
"url": "https://acme.example/pricing",
"kind": "crawl",
"fetchedAt": "2026-10-10T09:12:00Z"
},
{
"id": "src_2",
"url": "https://rival.example/faq",
"kind": "crawl",
"fetchedAt": "2026-10-10T09:13:00Z"
}
]
},
"words": {
"reading": "Reading…",
"failed": "Couldn't finish this part.",
"sources": "Sources",
"suggestions": "Suggestions",
"findings": "Findings",
"priority": "Priority",
"effort": "effort",
"impact": "Impact"
},
"effortWords": {
"small": "Small",
"medium": "Medium",
"large": "Large"
},
"kindWords": {
"crawl": "Page read",
"search": "Search",
"ai_answer": "AI answer",
"dataset": "Dataset",
"brief": "Brief"
}
}} />
</BlockSurface>
</Theme>
);
}Install
Import
import Block from '@/components/klarhimmel/blocks/snapshot-module';- snapshot/module
- About
- One research module of a snapshot as a card: reading (skeleton), ready (headline, summary, suggestions with priority and effort chips and an impact line, then findings, numbered source markers that link to the sources list in the card)…
- Category
- The live snapshot of a site: progress narration, the profile, one card per research module and the numbered sources behind it. Rendered in a page island that re-renders on each poll.
Notes
When to use it
One research module of a snapshot as a card, such as competitors or audience. It also shows the module while it is still running. Use `snapshot-progress` for the live narration above the cards and `snapshot-profile` for the card that introduces the site.
Writing for it
- The title (80 characters) names the module. Set status honestly, because it picks what is drawn: pending and running show a skeleton, unsure shows only the note, failed shows a fixed sentence, ready shows the output. - In output, headline holds 300 characters and summary 2000. Each item is a suggestion or a finding, and suggestions get priority and effort chips plus an impact line. - Link an item to a source by listing the source id in the item. The card then shows numbered markers that jump to the sources list inside the same card.
Watch out for
Nothing from output is drawn unless status is ready, and the note only when status is unsure. Setting output on a running card shows the skeleton anyway, and a marker pointing to a source id that does not exist is dropped.
Pairs well with
Usage
The block in a page, with its default content (long lists shortened). Every prop is in the table below.
import { Theme } from '@/components/klarhimmel/theme/style';
import { BlockSurface } from '@/components/klarhimmel/blocks/surface';
import SnapshotModule from '@/components/klarhimmel/blocks/snapshot-module';
export default function Section() {
return (
<Theme theme="brand">
<BlockSurface>
<SnapshotModule props={{
"title": "Competitors",
"status": "ready",
"note": "",
"output": {
"headline": "Three firms compete wit…",
"summary": "Two of them publish fix…",
"items": [
{
"id": "sug_1",
"kind": "suggestion",
"title": "Put your fixed monthly …",
"detail": "Both nearby firms show …",
"priority": "1",
"effort": "small",
"impact": "More people reach the c…",
"links": [
{
"label": "Their pricing page",
"url": "https://rival.example/p…"
}
],
"sources": [
"src_1"
]
}
],
"sources": [
{
"id": "src_1",
"url": "https://acme.example/pr…",
"kind": "crawl",
"fetchedAt": "2026-10-10T09:12:00Z"
}
]
},
"words": {
"reading": "Reading…",
"failed": "Couldn't finish this pa…",
"sources": "Sources",
"suggestions": "Suggestions",
"findings": "Findings",
"priority": "Priority",
"effort": "effort",
"impact": "Impact"
},
"effortWords": {
"small": "Small",
"medium": "Medium",
"large": "Large"
},
Props
The type, default and text limit of every prop. On a real page, over-limit text is kept and checkSections flags it (Installation, Check a page before you ship); this live preview shows the default until it fits. The panel above edits all props.
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | 'Competitors' | Text, up to 80 characters. |
status | 'pending' | 'running' | 'ready' | 'unsure' | 'failed' | 'ready' | One of 'pending', 'running', 'ready', 'unsure', 'failed'. |
note | string | '' | Text, up to 400 characters. Optional; empty is not rendered. |
output | { headline, summary, items, sources } | {…} | Fields: headline, summary, items, sources. Optional; empty is not rendered. |
collapse | { findings, sources } | - | Fields: findings (optional), sources (optional). Optional; empty is not rendered. |
words | { reading, failed, sources, suggestions, findings, priority, effort, impact } | {…} | Fields: reading (optional), failed (optional), sources (optional), suggestions (optional), findings (optional), priority (optional), effort (optional), impact (optional). Optional; empty is not rendered. |
effortWords | { small, medium, large } | {…} | Fields: small (optional), medium (optional), large (optional). Optional; empty is not rendered. |
kindWords | { crawl, search, ai_answer, dataset, brief } | {…} | Fields: crawl (optional), search (optional), ai_answer (optional), dataset (optional), brief (optional). Optional; empty is not rendered. |
headingLevel | '1' | '2' | - | One of '1', '2'. Optional; empty is not rendered. |