feat(ui): align workbench with Stitch screens
This commit is contained in:
@@ -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
|
||||
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
|
||||
|
||||
`App.tsx` remains the shared workspace orchestrator, while focused surfaces
|
||||
|
||||
Generated
+20
@@ -8,6 +8,8 @@
|
||||
"name": "geointel-frontend",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@fontsource/manrope": "^5.3.0",
|
||||
"@fontsource/public-sans": "^5.3.0",
|
||||
"lucide-react": "^1.25.0",
|
||||
"maplibre-gl": "^4.7.1",
|
||||
"react": "^18.2.0",
|
||||
@@ -898,6 +900,24 @@
|
||||
"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": {
|
||||
"version": "0.3.13",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/manrope": "^5.3.0",
|
||||
"@fontsource/public-sans": "^5.3.0",
|
||||
"lucide-react": "^1.25.0",
|
||||
"maplibre-gl": "^4.7.1",
|
||||
"react": "^18.2.0",
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
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/premium.css'
|
||||
import './styles/atlas-workbench.css'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'
|
||||
import { BoxSelect, MapPinned, SlidersHorizontal, Trash2 } from 'lucide-react'
|
||||
import GeoMap from '../GeoMap'
|
||||
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'
|
||||
@@ -1905,8 +1906,11 @@ export function MapWorkspace({
|
||||
onClick={() => setAdvancedMode(true)}
|
||||
aria-expanded={advancedMode}
|
||||
aria-controls="geo-advanced-workbench"
|
||||
aria-label="Geavanceerde werkbank"
|
||||
title="Geavanceerde werkbank"
|
||||
>
|
||||
Geavanceerde werkbank
|
||||
<SlidersHorizontal aria-hidden="true" />
|
||||
<span>Geavanceerde werkbank</span>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
@@ -2210,6 +2214,7 @@ export function MapWorkspace({
|
||||
type="button"
|
||||
onClick={startBboxSelection}
|
||||
>
|
||||
<BoxSelect aria-hidden="true" />
|
||||
{bboxSelectionMode ? 'Teken op de kaart…' : 'Teken rechthoek'}
|
||||
</button>
|
||||
<button
|
||||
@@ -2223,9 +2228,11 @@ export function MapWorkspace({
|
||||
}
|
||||
onClick={() => selectedAreaBbox && void analyzeSelection(selectedAreaBbox, selectedMapArea?.id)}
|
||||
>
|
||||
<MapPinned aria-hidden="true" />
|
||||
{regionalRasterThemeActive || regionalOnDemandThemeActive ? 'Selecteer een deelgebied' : 'Volledig werkgebied'}
|
||||
</button>
|
||||
<button className="secondary-action" disabled={!mapSelectionBbox} type="button" onClick={clearAreaSelection}>
|
||||
<Trash2 aria-hidden="true" />
|
||||
Wis selectie
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -208,14 +208,48 @@ export function QualityResultsPanel({
|
||||
</div>
|
||||
|
||||
{qualityChecks.length === 0 ? (
|
||||
<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 className="quality-empty-workbench" aria-label="Lege kwaliteitswerkruimte">
|
||||
<aside className="quality-empty-context">
|
||||
<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>
|
||||
) : null}
|
||||
|
||||
{qualityChecks.length > 0 ? (
|
||||
<details className="quality-advanced-disclosure">
|
||||
<details className="quality-advanced-disclosure" open>
|
||||
<summary>
|
||||
<span>Details, kaartbewijs en historiek</span>
|
||||
<strong>{qualityChecks.length} bewaarde controles</strong>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user