feat(ui): align workbench with Stitch screens
This commit is contained in:
@@ -13,6 +13,14 @@
|
|||||||
Atlas Workbench. The new shell uses one compact icon navigation rail, one
|
Atlas Workbench. The new shell uses one compact icon navigation rail, one
|
||||||
context bar and task-specific work surfaces across Map, Sources, AI
|
context bar and task-specific work surfaces across Map, Sources, AI
|
||||||
Questions, Quality, Image Analysis, Downloads, Status and Administration.
|
Questions, Quality, Image Analysis, Downloads, Status and Administration.
|
||||||
|
- Completed a screen-by-screen Stitch parity pass with dedicated designs for
|
||||||
|
Quality, Image Analysis, Downloads and Status/Administration. Sources,
|
||||||
|
Quality, Image Analysis and Downloads now use the same master-detail and
|
||||||
|
inspector structures as their Stitch references instead of generic panel
|
||||||
|
stacks.
|
||||||
|
- Bundled Public Sans and Manrope locally and aligned the implementation with
|
||||||
|
the exact Stitch canvas, context, ink, border, teal, steel and amber tokens.
|
||||||
|
No API, persistence, GIS or AI behavior changed.
|
||||||
- Restored the normal desktop map to one stable theme/map/insight row, made
|
- Restored the normal desktop map to one stable theme/map/insight row, made
|
||||||
the map absorb ultrawide space, bounded the mobile theme list and removed
|
the map absorb ultrawide space, bounded the mobile theme list and removed
|
||||||
the duplicate workspace command bar. API, database, GIS and AI behavior are
|
the duplicate workspace command bar. API, database, GIS and AI behavior are
|
||||||
|
|||||||
@@ -10861,3 +10861,51 @@ Behavior preservation:
|
|||||||
calculation, model runtime or persistence flow changed.
|
calculation, model runtime or persistence flow changed.
|
||||||
- Existing map selection, source loading, local Ollama, QA, analysis and
|
- Existing map selection, source loading, local Ollama, QA, analysis and
|
||||||
download actions remain wired through their original hooks and services.
|
download actions remain wired through their original hooks and services.
|
||||||
|
|
||||||
|
## 2026-07-19 - Stitch screen parity and responsive refinement
|
||||||
|
|
||||||
|
Implemented:
|
||||||
|
|
||||||
|
- Extended the Stitch project with dedicated Quality, Image Analysis,
|
||||||
|
Downloads and Status/Administration screens, all using design-system asset
|
||||||
|
`4667932515738184526`.
|
||||||
|
- Replaced the residual dark navigation treatment with the white 88-pixel
|
||||||
|
Stitch rail, pale context bar and locally bundled Public Sans/Manrope
|
||||||
|
typography.
|
||||||
|
- Made Sources a deterministic three-pane workspace after removing a legacy
|
||||||
|
full-width catalogue override.
|
||||||
|
- Added the Stitch control/result/inspector structure to the empty Quality
|
||||||
|
state and kept the existing populated evidence/history implementation.
|
||||||
|
- Compacted detection model administration into one row above the existing
|
||||||
|
configuration/result/QA workbench.
|
||||||
|
- Reorganized Downloads as artifact actions, current/history results and a
|
||||||
|
preview inspector without changing export callbacks or formats.
|
||||||
|
- Kept the MapLibre map full-height with icon controls and stable rails on
|
||||||
|
normal and ultrawide displays.
|
||||||
|
|
||||||
|
Visual verification:
|
||||||
|
|
||||||
|
- compared Map, Sources, AI Questions, Quality, Image Analysis, Downloads,
|
||||||
|
Status and Administration against their dedicated Stitch references;
|
||||||
|
- reviewed live-backend states at 1280x720, 1920x1080 and 390x844;
|
||||||
|
- confirmed that the widescreen map absorbs the additional width and that the
|
||||||
|
mobile workspaces remain vertically navigable without document overflow.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
|
||||||
|
- the complete readiness gate passed 1,052 backend tests, 22 frontend tests,
|
||||||
|
frontend typecheck/build and Alembic head `202607160001`;
|
||||||
|
- the final UX browser audit passed at 390x844, 1366x768 and 2560x1080 with
|
||||||
|
zero horizontal overflow, console errors or failed requests;
|
||||||
|
- all seven Belgium/North Sea release journeys passed through the redesigned
|
||||||
|
local frontend against the live backend;
|
||||||
|
- the journey retry caught and verified a fixed Sources grid containment issue
|
||||||
|
that previously allowed the Area panel to intercept a scrolled Project
|
||||||
|
management control.
|
||||||
|
|
||||||
|
Behavior preservation:
|
||||||
|
|
||||||
|
- no backend, API contract, migration, persistence, GIS metric, provider,
|
||||||
|
Ollama or model-runtime behavior changed;
|
||||||
|
- all existing actions continue through the original React hooks and service
|
||||||
|
layer.
|
||||||
|
|||||||
@@ -15,9 +15,15 @@ The redesign was developed in Stitch under:
|
|||||||
- Map Explorer screen: `c24113d1f1474c91b332b2365be24993`
|
- Map Explorer screen: `c24113d1f1474c91b332b2365be24993`
|
||||||
- Sources screen: `239796f2d66a44e7983e5fc588305ff8`
|
- Sources screen: `239796f2d66a44e7983e5fc588305ff8`
|
||||||
- AI Questions screen: `246aa57bbe974861885325ff9d10c6bd`
|
- AI Questions screen: `246aa57bbe974861885325ff9d10c6bd`
|
||||||
|
- Quality screen: `06b4b69387d847a0bba33c6953563860`
|
||||||
|
- Image Analysis screen: `200a196f4e524c979167e40905ae87f2`
|
||||||
|
- Downloads screen: `f6d91a48e98141bb94f680f626078a1e`
|
||||||
|
- Status and Administration screen: `3d685f83c61d4e9687bdfdf608220b26`
|
||||||
|
|
||||||
The React implementation remains the source of truth for behavior. Stitch is
|
The React implementation remains the source of truth for behavior. Stitch is
|
||||||
the design reference for hierarchy, spacing and component treatment.
|
the design reference for hierarchy, spacing and component treatment. Each
|
||||||
|
primary workspace has a dedicated Stitch screen; new layout work must compare
|
||||||
|
against the corresponding screen rather than only borrowing the color palette.
|
||||||
|
|
||||||
## Product hierarchy
|
## Product hierarchy
|
||||||
|
|
||||||
@@ -37,6 +43,12 @@ command bars or competing shortcut rows must not be reintroduced.
|
|||||||
|
|
||||||
- Desktop uses an 88-pixel navigation rail and a 56-pixel context bar.
|
- Desktop uses an 88-pixel navigation rail and a 56-pixel context bar.
|
||||||
- The normal map layout is `theme drawer / map / insight inspector`.
|
- The normal map layout is `theme drawer / map / insight inspector`.
|
||||||
|
- Sources uses `workspace and area / source inventory / loaded datasets`.
|
||||||
|
- AI Questions uses `area context / conversation and composer`.
|
||||||
|
- Quality uses `controls / result history / evidence inspector`.
|
||||||
|
- Image Analysis uses `configuration / persisted results / QA`.
|
||||||
|
- Downloads uses `artifact actions / export history / preview inspector`.
|
||||||
|
- Administration uses `source category / provider status and provenance`.
|
||||||
- Theme and insight rails stay stable on ultrawide displays; the map receives
|
- Theme and insight rails stay stable on ultrawide displays; the map receives
|
||||||
the additional width.
|
the additional width.
|
||||||
- Non-map workspaces use one task header and one primary work surface.
|
- Non-map workspaces use one task header and one primary work surface.
|
||||||
@@ -50,17 +62,21 @@ command bars or competing shortcut rows must not be reintroduced.
|
|||||||
|
|
||||||
| Role | Value |
|
| Role | Value |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Canvas | `#f3f6f5` |
|
| Canvas | `#f5f7f6` |
|
||||||
| Surface | `#ffffff` |
|
| Surface | `#ffffff` |
|
||||||
| Ink | `#152522` |
|
| Pale context | `#eef8f5` |
|
||||||
| Muted text | `#687773` |
|
| Ink | `#162622` |
|
||||||
| Border | `#dce4e1` |
|
| Muted text | `#64726f` |
|
||||||
|
| Border | `#e1e7e5` |
|
||||||
| Primary teal | `#0b6b62` |
|
| Primary teal | `#0b6b62` |
|
||||||
| Context blue | `#315d73` |
|
| Context blue | `#315d73` |
|
||||||
| Attention amber | `#a55c23` |
|
| Attention amber | `#b46432` |
|
||||||
| Error red | `#a33c39` |
|
| Error red | `#a33c39` |
|
||||||
| Radius | `4px` |
|
| Radius | `4px` |
|
||||||
|
|
||||||
|
Body and labels use locally bundled Public Sans. Headings use locally bundled
|
||||||
|
Manrope. The interface must not depend on a remote font request.
|
||||||
|
|
||||||
The UI does not use gradients, decorative blobs, oversized hero sections,
|
The UI does not use gradients, decorative blobs, oversized hero sections,
|
||||||
nested cards or pill-heavy status presentation.
|
nested cards or pill-heavy status presentation.
|
||||||
|
|
||||||
@@ -84,6 +100,8 @@ nested cards or pill-heavy status presentation.
|
|||||||
`frontend/src/styles/atlas-workbench.css`
|
`frontend/src/styles/atlas-workbench.css`
|
||||||
- Map workflow:
|
- Map workflow:
|
||||||
`frontend/src/components/map/MapWorkspace.tsx`
|
`frontend/src/components/map/MapWorkspace.tsx`
|
||||||
|
- Empty and populated quality review:
|
||||||
|
`frontend/src/components/quality/QualityResultsPanel.tsx`
|
||||||
- API, persistence and GIS behavior remain outside the design system.
|
- API, persistence and GIS behavior remain outside the design system.
|
||||||
|
|
||||||
Any future visual change must retain the browser acceptance widths of
|
Any future visual change must retain the browser acceptance widths of
|
||||||
|
|||||||
@@ -127,6 +127,16 @@ The visual contract, Stitch project and screen references are documented in
|
|||||||
hierarchy only; API, persistence and GIS behavior remain owned by the existing
|
hierarchy only; API, persistence and GIS behavior remain owned by the existing
|
||||||
hooks and services.
|
hooks and services.
|
||||||
|
|
||||||
|
All eight user-facing destinations now use the Stitch Atlas composition
|
||||||
|
directly. Map is a flush theme/canvas/insight surface; Sources is a
|
||||||
|
workspace/catalog/dataset master-detail view; AI Questions keeps context beside
|
||||||
|
the conversation; Quality keeps controls, results and evidence in three stable
|
||||||
|
panes; Image Analysis keeps run configuration, persisted results and QA aligned;
|
||||||
|
Downloads separates artifact actions, history and preview; Status and
|
||||||
|
Administration use compact operational rows. Public Sans and Manrope are
|
||||||
|
bundled with the frontend, so typography remains identical without a remote
|
||||||
|
font dependency.
|
||||||
|
|
||||||
## Current component boundaries
|
## Current component boundaries
|
||||||
|
|
||||||
`App.tsx` remains the shared workspace orchestrator, while focused surfaces
|
`App.tsx` remains the shared workspace orchestrator, while focused surfaces
|
||||||
|
|||||||
Generated
+20
@@ -8,6 +8,8 @@
|
|||||||
"name": "geointel-frontend",
|
"name": "geointel-frontend",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/manrope": "^5.3.0",
|
||||||
|
"@fontsource/public-sans": "^5.3.0",
|
||||||
"lucide-react": "^1.25.0",
|
"lucide-react": "^1.25.0",
|
||||||
"maplibre-gl": "^4.7.1",
|
"maplibre-gl": "^4.7.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -898,6 +900,24 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource/manrope": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/manrope/-/manrope-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-obJ1Dv3+uCA6HlHgW8u4BGYxJR9In2HW7gjJhlflEvkrj1X1iSEwu0fToL+JYGC/FEKFfIz1sBuPduvcL2gIAA==",
|
||||||
|
"license": "OFL-1.1",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@fontsource/public-sans": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource/public-sans/-/public-sans-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-kjODI0S3zdv0mBYCIQ8TbBayaiqszpc2UbhJiO3bjIqVVXzcWfHSt2o3WBCLOY3juaGaQoy4MoWCcgmfI5hCuA==",
|
||||||
|
"license": "OFL-1.1",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource/manrope": "^5.3.0",
|
||||||
|
"@fontsource/public-sans": "^5.3.0",
|
||||||
"lucide-react": "^1.25.0",
|
"lucide-react": "^1.25.0",
|
||||||
"maplibre-gl": "^4.7.1",
|
"maplibre-gl": "^4.7.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import '@fontsource/manrope/latin-500.css'
|
||||||
|
import '@fontsource/manrope/latin-600.css'
|
||||||
|
import '@fontsource/manrope/latin-700.css'
|
||||||
|
import '@fontsource/public-sans/latin-400.css'
|
||||||
|
import '@fontsource/public-sans/latin-500.css'
|
||||||
|
import '@fontsource/public-sans/latin-600.css'
|
||||||
import './styles/app.css'
|
import './styles/app.css'
|
||||||
import './styles/premium.css'
|
import './styles/premium.css'
|
||||||
import './styles/atlas-workbench.css'
|
import './styles/atlas-workbench.css'
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'
|
||||||
|
import { BoxSelect, MapPinned, SlidersHorizontal, Trash2 } from 'lucide-react'
|
||||||
import GeoMap from '../GeoMap'
|
import GeoMap from '../GeoMap'
|
||||||
import type { AreaRead, CoverageResolveResponse, CoverageStatus, DatasetCreateResponse, DetectionQaResult, MapResultExportRequest, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
|
import type { AreaRead, CoverageResolveResponse, CoverageStatus, DatasetCreateResponse, DetectionQaResult, MapResultExportRequest, MapViewportState, OrthophotoAcquisitionResult, OrthophotoProductRead, ProjectRead, QaComparisonResult, VectorSelectionBBox, VectorSelectionMetric, VectorSelectionResponse } from '../../types'
|
||||||
import { useMapThemeSelectionInsights, type MapThemeAcquisition, type MapThemeQuery } from '../../hooks/useMapThemeSelectionInsights'
|
import { useMapThemeSelectionInsights, type MapThemeAcquisition, type MapThemeQuery } from '../../hooks/useMapThemeSelectionInsights'
|
||||||
@@ -1905,8 +1906,11 @@ export function MapWorkspace({
|
|||||||
onClick={() => setAdvancedMode(true)}
|
onClick={() => setAdvancedMode(true)}
|
||||||
aria-expanded={advancedMode}
|
aria-expanded={advancedMode}
|
||||||
aria-controls="geo-advanced-workbench"
|
aria-controls="geo-advanced-workbench"
|
||||||
|
aria-label="Geavanceerde werkbank"
|
||||||
|
title="Geavanceerde werkbank"
|
||||||
>
|
>
|
||||||
Geavanceerde werkbank
|
<SlidersHorizontal aria-hidden="true" />
|
||||||
|
<span>Geavanceerde werkbank</span>
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -2210,6 +2214,7 @@ export function MapWorkspace({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={startBboxSelection}
|
onClick={startBboxSelection}
|
||||||
>
|
>
|
||||||
|
<BoxSelect aria-hidden="true" />
|
||||||
{bboxSelectionMode ? 'Teken op de kaart…' : 'Teken rechthoek'}
|
{bboxSelectionMode ? 'Teken op de kaart…' : 'Teken rechthoek'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@@ -2223,9 +2228,11 @@ export function MapWorkspace({
|
|||||||
}
|
}
|
||||||
onClick={() => selectedAreaBbox && void analyzeSelection(selectedAreaBbox, selectedMapArea?.id)}
|
onClick={() => selectedAreaBbox && void analyzeSelection(selectedAreaBbox, selectedMapArea?.id)}
|
||||||
>
|
>
|
||||||
|
<MapPinned aria-hidden="true" />
|
||||||
{regionalRasterThemeActive || regionalOnDemandThemeActive ? 'Selecteer een deelgebied' : 'Volledig werkgebied'}
|
{regionalRasterThemeActive || regionalOnDemandThemeActive ? 'Selecteer een deelgebied' : 'Volledig werkgebied'}
|
||||||
</button>
|
</button>
|
||||||
<button className="secondary-action" disabled={!mapSelectionBbox} type="button" onClick={clearAreaSelection}>
|
<button className="secondary-action" disabled={!mapSelectionBbox} type="button" onClick={clearAreaSelection}>
|
||||||
|
<Trash2 aria-hidden="true" />
|
||||||
Wis selectie
|
Wis selectie
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -208,14 +208,48 @@ export function QualityResultsPanel({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{qualityChecks.length === 0 ? (
|
{qualityChecks.length === 0 ? (
|
||||||
<div className="result-state result-state-empty quality-user-empty-state">
|
<div className="quality-empty-workbench" aria-label="Lege kwaliteitswerkruimte">
|
||||||
<strong>Nog geen kwaliteitscontrole uitgevoerd</strong>
|
<aside className="quality-empty-context">
|
||||||
<p>Selecteer een gebied op de kaart en vergelijk een bewaard resultaat met een officiële referentielaag.</p>
|
<span className="eyebrow">Controles</span>
|
||||||
|
<strong>Nog geen resultaten</strong>
|
||||||
|
<p>Kwaliteitscontroles verschijnen hier nadat een resultaat met een officiële referentielaag is vergeleken.</p>
|
||||||
|
<div className="quality-empty-context-stat">
|
||||||
|
<span>Te controleren lagen</span>
|
||||||
|
<strong>{candidateDatasets.length}</strong>
|
||||||
|
</div>
|
||||||
|
<div className="quality-empty-context-stat">
|
||||||
|
<span>Referentielagen</span>
|
||||||
|
<strong>{referenceDatasets.length}</strong>
|
||||||
|
</div>
|
||||||
|
<button type="button" className="secondary-action" onClick={onRefresh} disabled={!selectedProjectId}>
|
||||||
|
Resultaten vernieuwen
|
||||||
|
</button>
|
||||||
|
</aside>
|
||||||
|
<div className="quality-empty-results">
|
||||||
|
<div className="quality-empty-column-heading">
|
||||||
|
<strong>Resultaten</strong>
|
||||||
|
<span>0 controles</span>
|
||||||
|
</div>
|
||||||
|
<div className="result-state result-state-empty quality-user-empty-state">
|
||||||
|
<strong>Nog geen kwaliteitscontrole uitgevoerd</strong>
|
||||||
|
<p>Selecteer een gebied op de kaart en vergelijk een bewaard resultaat met een officiële referentielaag.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<aside className="quality-empty-inspector">
|
||||||
|
<div className="quality-empty-column-heading">
|
||||||
|
<strong>Controle-inspector</strong>
|
||||||
|
<span>Geen selectie</span>
|
||||||
|
</div>
|
||||||
|
<div className="result-state result-state-empty">
|
||||||
|
<strong>Geen bewijs geselecteerd</strong>
|
||||||
|
<p>Scores, databronnen en kaartbewijs worden hier samen getoond zodra een controle beschikbaar is.</p>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{qualityChecks.length > 0 ? (
|
{qualityChecks.length > 0 ? (
|
||||||
<details className="quality-advanced-disclosure">
|
<details className="quality-advanced-disclosure" open>
|
||||||
<summary>
|
<summary>
|
||||||
<span>Details, kaartbewijs en historiek</span>
|
<span>Details, kaartbewijs en historiek</span>
|
||||||
<strong>{qualityChecks.length} bewaarde controles</strong>
|
<strong>{qualityChecks.length} bewaarde controles</strong>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user