Detail state screen
canonMinimal record-detail frame (back button + one line) for loading and not-found; same header geometry as the loaded detail.
Coupled to person-record.css: a detail route that does not load that sheet renders this frame unstyled.
Used in 2 files · 2 areas · 2× — pages/ProjectDetailPage, pages/UkolDetailPage
@acrm/ui <DetailStateScreen>.pr .pr-top .pr-ico .pr-name-topSourceStoryLegacy card Loading (skeleton).htmlDefault
Načítám…
export const Default = () => (
<div style={{ width: 560 }}>
<DetailStateScreen title="Načítám…" onBack={() => {}} />
</div>
);Variants
loading — the route resolved, the record has not arrived yet
not found — the id is wrong or the record was deleted; the only way on is back
own back tooltip — say where back leads when it is not the previous page
export const Variants = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)', width: 560 }}>
<Labeled text="loading — the route resolved, the record has not arrived yet">
<DetailStateScreen title="Načítám…" onBack={() => {}} />
</Labeled>
<Labeled text="not found — the id is wrong or the record was deleted; the only way on is back">
<DetailStateScreen title="Osoba nenalezena" onBack={() => {}} />
</Labeled>
<Labeled text="own back tooltip — say where back leads when it is not the previous page">
<DetailStateScreen title="Obchod nenalezen" backLabel="Zpět na obchody" onBack={() => {}} />
</Labeled>
</div>
);States
switch between the three — the back button and the title sit on the same baseline in all of them, so nothing jumps when the record lands
export const States = () => {
const [state, setState] = useState<'loading' | 'found' | 'missing'>('loading');
return (
<div style={{ width: 560, display: 'grid', gap: 'var(--sp-3)' }}>
<div style={{ display: 'flex', gap: 'var(--sp-2)' }}>
<Button onClick={() => setState('loading')}>Načítám</Button>
<Button onClick={() => setState('found')}>Načteno</Button>
<Button onClick={() => setState('missing')}>Nenalezeno</Button>
</div>
<div
style={{
border: '1px solid var(--border)',
borderRadius: 'var(--radius-md)',
overflow: 'hidden',
background: 'var(--bg-canvas)',
}}
>
{state === 'found' ? (
<div className="pr">
<div className="pr-top">
<IconButton icon="arrow-left" title="Zpět" aria-label="Zpět" />
<span className="pr-name-top" style={{ marginLeft: 'var(--sp-3)' }}>
Jan Novák
</span>
</div>
</div>
) : (
<DetailStateScreen
title={state === 'loading' ? 'Načítám…' : 'Osoba nenalezena'}
onBack={() => {}}
/>
)}
</div>
<span style={label}>
switch between the three — the back button and the title sit on the same baseline in all of
them, so nothing jumps when the record lands
</span>
</div>
);
};Composition
detail frame + skeleton body — the honest loading screen: header now, content shaped like the content
…and where the siblings belong: failed load takes the error tone with a retry
…and a loaded record with an empty section takes EmptyState
export const Composition = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)', width: 560 }}>
<Labeled text="detail frame + skeleton body — the honest loading screen: header now, content shaped like the content">
<>
<DetailStateScreen title="Načítám…" onBack={() => {}} />
<div style={{ padding: 'var(--sp-4)', display: 'grid', gap: 'var(--sp-3)' }}>
<SkLine w={220} lg />
<SkLine w="100%" />
<SkLine w="72%" />
</div>
</>
</Labeled>
<Labeled text="…and where the siblings belong: failed load takes the error tone with a retry">
<EmptyState
tone="error"
title="Detail se nenačetl"
size="sm"
action={{ onClick: () => {} }}
/>
</Labeled>
<Labeled text="…and a loaded record with an empty section takes EmptyState">
<EmptyState size="sm" icon="note" title="Žádná poznámka" />
</Labeled>
</div>
);