fix(atlas): visual empty stats state

This commit is contained in:
jubnl
2026-08-22 18:04:38 +02:00
parent e9090fa33c
commit e91ad69c83
3 changed files with 15 additions and 5 deletions
+10 -1
View File
@@ -10,6 +10,10 @@ import MDancingTrek, { type TrekScene, type TrekMood } from '../../mobile/compon
* so we map them onto the desktop palette here. Its `.trek-*` choreography is
* global CSS, so it animates outside the shell as-is. `surface` should match the
* background the state sits on so the cut-out eyes read as holes (default: card).
*
* `layout="row"` puts the mascot beside the title with tight padding, for short
* content-sized panels (the Atlas glass pill) where the stacked look towers over
* the sibling states.
*/
export default function EmptyState({
scene = 'idle',
@@ -17,6 +21,7 @@ export default function EmptyState({
title,
size = 104,
surface = 'var(--bg-card)',
layout = 'stack',
className = '',
action,
}: {
@@ -25,13 +30,17 @@ export default function EmptyState({
title: string
size?: number
surface?: string
layout?: 'stack' | 'row'
className?: string
/** Optional call to action under the title, for states that have an obvious next step. */
action?: ReactNode
}) {
const layoutClasses = layout === 'row'
? 'flex flex-row items-center justify-center gap-3 px-6 py-3'
: 'flex flex-col items-center justify-center gap-3 px-6 py-12 text-center'
return (
<div
className={`flex flex-col items-center justify-center gap-3 px-6 py-12 text-center ${className}`}
className={`${layoutClasses} ${className}`}
style={{ '--m-ink': 'var(--text-primary)', '--m-bg': surface } as CSSProperties}
>
<MDancingTrek scene={scene} mood={mood} size={size} />
+1 -1
View File
@@ -525,7 +525,7 @@ function SidebarContent({ data, stats, countries, selectedCountry, countryDetail
return (
<>
{tabBar}
<EmptyState scene="atlas" title={t('atlas.noData')} />
<EmptyState scene="atlas" title={t('atlas.noData')} layout="row" size={52} />
</>
)
}
+4 -3
View File
@@ -181,9 +181,10 @@ Ordered by value:
'write' }` appears ~100+ times across `.mcp.ts` files as free strings. A typo'd group
never matches a real scope: scoped tokens get denied (fail closed) but `scopes: null`
sessions pass (fail open) — silent scope-model drift either way. Mechanism: derive a
`ScopeGroup` union from `SCOPES` and type the decorator's `access.group` against it via
the same `declare module '@trek/nest-mcp'` augmentation already used for `McpContext`
(keeps nest-mcp extraction-clean); plus a **boot gate in the MCP registry**: at discovery
`ScopeGroup` union from `SCOPES` and type the decorator's `access.group` against it
(originally a `declare module '@trek/nest-mcp'` augmentation; since the 2026-08-22 fold
the registries live directly in `server/src/nest-mcp/types.ts`); plus a **boot gate in
the MCP registry**: at discovery
time, refuse to boot on an `access.group`/tool-name/`when` combination that doesn't
resolve against `SCOPES` — the body-contract ratchet pattern applied to the MCP surface.
The registry the user-facing scopes UI reads (`SCOPE_INFO`) then serves decorators, the