Skip to content

Commit e91ad69

Browse files
committed
fix(atlas): visual empty stats state
1 parent e9090fa commit e91ad69

3 files changed

Lines changed: 15 additions & 5 deletions

File tree

client/src/components/shared/EmptyState.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ import MDancingTrek, { type TrekScene, type TrekMood } from '../../mobile/compon
1010
* so we map them onto the desktop palette here. Its `.trek-*` choreography is
1111
* global CSS, so it animates outside the shell as-is. `surface` should match the
1212
* background the state sits on so the cut-out eyes read as holes (default: card).
13+
*
14+
* `layout="row"` puts the mascot beside the title with tight padding, for short
15+
* content-sized panels (the Atlas glass pill) where the stacked look towers over
16+
* the sibling states.
1317
*/
1418
export default function EmptyState({
1519
scene = 'idle',
1620
mood,
1721
title,
1822
size = 104,
1923
surface = 'var(--bg-card)',
24+
layout = 'stack',
2025
className = '',
2126
action,
2227
}: {
@@ -25,13 +30,17 @@ export default function EmptyState({
2530
title: string
2631
size?: number
2732
surface?: string
33+
layout?: 'stack' | 'row'
2834
className?: string
2935
/** Optional call to action under the title, for states that have an obvious next step. */
3036
action?: ReactNode
3137
}) {
38+
const layoutClasses = layout === 'row'
39+
? 'flex flex-row items-center justify-center gap-3 px-6 py-3'
40+
: 'flex flex-col items-center justify-center gap-3 px-6 py-12 text-center'
3241
return (
3342
<div
34-
className={`flex flex-col items-center justify-center gap-3 px-6 py-12 text-center ${className}`}
43+
className={`${layoutClasses} ${className}`}
3544
style={{ '--m-ink': 'var(--text-primary)', '--m-bg': surface } as CSSProperties}
3645
>
3746
<MDancingTrek scene={scene} mood={mood} size={size} />

client/src/pages/AtlasPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ function SidebarContent({ data, stats, countries, selectedCountry, countryDetail
525525
return (
526526
<>
527527
{tabBar}
528-
<EmptyState scene="atlas" title={t('atlas.noData')} />
528+
<EmptyState scene="atlas" title={t('atlas.noData')} layout="row" size={52} />
529529
</>
530530
)
531531
}

roadmap.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,10 @@ Ordered by value:
181181
'write' }` appears ~100+ times across `.mcp.ts` files as free strings. A typo'd group
182182
never matches a real scope: scoped tokens get denied (fail closed) but `scopes: null`
183183
sessions pass (fail open) — silent scope-model drift either way. Mechanism: derive a
184-
`ScopeGroup` union from `SCOPES` and type the decorator's `access.group` against it via
185-
the same `declare module '@trek/nest-mcp'` augmentation already used for `McpContext`
186-
(keeps nest-mcp extraction-clean); plus a **boot gate in the MCP registry**: at discovery
184+
`ScopeGroup` union from `SCOPES` and type the decorator's `access.group` against it
185+
(originally a `declare module '@trek/nest-mcp'` augmentation; since the 2026-08-22 fold
186+
the registries live directly in `server/src/nest-mcp/types.ts`); plus a **boot gate in
187+
the MCP registry**: at discovery
187188
time, refuse to boot on an `access.group`/tool-name/`when` combination that doesn't
188189
resolve against `SCOPES` — the body-contract ratchet pattern applied to the MCP surface.
189190
The registry the user-facing scopes UI reads (`SCOPE_INFO`) then serves decorators, the

0 commit comments

Comments
 (0)