feat(ui): redesign GeoIntel as Atlas Workbench
This commit is contained in:
+48
-78
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import './styles/app.css'
|
||||
import './styles/premium.css'
|
||||
import './styles/visual-polish.css'
|
||||
import './styles/atlas-workbench.css'
|
||||
import { ChangeDetectionPanel } from './components/analysis/ChangeDetectionPanel'
|
||||
import { GeoAssistantPanel } from './components/assistant/GeoAssistantPanel'
|
||||
import { DatasetPanel } from './components/datasets/DatasetPanel'
|
||||
@@ -18,6 +18,11 @@ import { QualityResultsPanel } from './components/quality/QualityResultsPanel'
|
||||
import type { DatasetCreateResponse } from './types'
|
||||
import { ProviderPanel } from './components/providers/ProviderPanel'
|
||||
import { SegmentationLab } from './components/segmentation/SegmentationLab'
|
||||
import {
|
||||
WorkbenchNavigation,
|
||||
type WorkspaceNavigationGroup,
|
||||
type WorkspaceNavigationItem,
|
||||
} from './components/shell/WorkbenchNavigation'
|
||||
import { useChangeDetectionWorkflow } from './hooks/useChangeDetectionWorkflow'
|
||||
import { useDemoWorkflow } from './hooks/useDemoWorkflow'
|
||||
import { useCoverageResolver } from './hooks/useCoverageResolver'
|
||||
@@ -51,7 +56,7 @@ function isVectorDatasetType(datasetType: string): boolean {
|
||||
return datasetType === 'vector' || datasetType === 'geojson'
|
||||
}
|
||||
|
||||
const workspaceNavItems: Array<{ key: WorkspaceKey; label: string; description: string }> = [
|
||||
const workspaceNavItems: WorkspaceNavigationItem[] = [
|
||||
{ key: 'overview', label: 'Status', description: 'Beschikbaarheid en aandachtspunten' },
|
||||
{ key: 'data', label: 'Bronnen', description: 'Gebieden en ingeladen gegevens' },
|
||||
{ key: 'map', label: 'Kaart', description: 'Selecteren, uitlezen en vergelijken' },
|
||||
@@ -62,7 +67,7 @@ const workspaceNavItems: Array<{ key: WorkspaceKey; label: string; description:
|
||||
{ key: 'system', label: 'Beheer', description: 'Databronnen en systeemstatus' },
|
||||
]
|
||||
|
||||
const workspaceNavGroups: Array<{ label: string; keys: WorkspaceKey[] }> = [
|
||||
const workspaceNavGroups: WorkspaceNavigationGroup[] = [
|
||||
{ label: 'Verkennen', keys: ['map', 'data'] },
|
||||
{ label: 'Vragen', keys: ['assistant'] },
|
||||
{ label: 'Analyseren', keys: ['analysis', 'ai'] },
|
||||
@@ -779,71 +784,52 @@ function App(): JSX.Element {
|
||||
>
|
||||
Ga naar de werkruimte
|
||||
</a>
|
||||
<header className="workbench-topbar">
|
||||
<div className="brand-block">
|
||||
<span className="brand-mark" aria-hidden="true">GI</span>
|
||||
<div>
|
||||
<h1>GeoIntel</h1>
|
||||
<p>GeoAI-werkruimte · gebiedsdata en analyse</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="context-bar" aria-label="Actieve werkcontext">
|
||||
<div>
|
||||
<span>Werkruimte</span>
|
||||
<strong title={projectContextLabel}>{projectContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Gebied</span>
|
||||
<strong title={areaContextLabel}>{areaContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Bron</span>
|
||||
<strong title={datasetContextLabel}>{datasetContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Kaartlaag</span>
|
||||
<strong title={layerContextLabel}>{layerContextLabel}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<p className="sr-only" role="status" aria-live="polite">{workspaceStatusMessage}</p>
|
||||
{errorMessage ? <p className="error" role="alert">{errorMessage}</p> : null}
|
||||
|
||||
<div className="workbench-layout">
|
||||
<aside className="workbench-sidebar" aria-label="Navigatie van de werkruimte">
|
||||
<nav aria-label="Hoofdonderdelen">
|
||||
{workspaceNavGroups.map((group) => (
|
||||
<div className="nav-group" key={group.label}>
|
||||
<p className="nav-section-label">{group.label}</p>
|
||||
{group.keys.map((key) => {
|
||||
const item = workspaceNavItems.find((candidate) => candidate.key === key)
|
||||
if (!item) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className={item.key === activeWorkspace ? 'nav-item nav-item-active' : 'nav-item'}
|
||||
onClick={() => setActiveWorkspace(item.key)}
|
||||
aria-current={item.key === activeWorkspace ? 'page' : undefined}
|
||||
aria-label={`Open ${item.label}: ${item.description}`}
|
||||
data-testid={`workspace-nav-${item.key}`}
|
||||
>
|
||||
<span>{item.label}</span>
|
||||
<small>{item.description}</small>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
<WorkbenchNavigation
|
||||
activeWorkspace={activeWorkspace}
|
||||
groups={workspaceNavGroups}
|
||||
items={workspaceNavItems}
|
||||
onSelect={setActiveWorkspace}
|
||||
/>
|
||||
|
||||
<div className="workbench-stage">
|
||||
<header className="workbench-topbar">
|
||||
<div className="mobile-brand">
|
||||
<span className="brand-mark" aria-hidden="true">GI</span>
|
||||
<strong>GeoIntel</strong>
|
||||
</div>
|
||||
<div className="context-bar" aria-label="Actieve werkcontext">
|
||||
<div>
|
||||
<span>Werkruimte</span>
|
||||
<strong title={projectContextLabel}>{projectContextLabel}</strong>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
<div>
|
||||
<span>Gebied</span>
|
||||
<strong title={areaContextLabel}>{areaContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Bron</span>
|
||||
<strong title={datasetContextLabel}>{datasetContextLabel}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Kaartlaag</span>
|
||||
<strong title={layerContextLabel}>{layerContextLabel}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div className="context-health" aria-label="Systeemstatus">
|
||||
<span aria-hidden="true" />
|
||||
<strong>{workspaceDataLoading ? 'Laden' : errorMessage ? 'Aandacht' : 'Gereed'}</strong>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="workbench-content">
|
||||
|
||||
<main
|
||||
ref={workbenchMainRef}
|
||||
className="workbench-main"
|
||||
className={activeWorkspace === 'map' ? 'workbench-main workbench-main-map' : 'workbench-main'}
|
||||
id="workspace-main"
|
||||
tabIndex={-1}
|
||||
aria-busy={workspaceDataLoading}
|
||||
@@ -868,24 +854,6 @@ function App(): JSX.Element {
|
||||
) : null}
|
||||
</div>
|
||||
</div> : null}
|
||||
<div className="workspace-command-bar" aria-label="Snelkoppelingen">
|
||||
<div className="workspace-nav-cluster">
|
||||
{workspaceNavItems.slice(0, 5).map((item) => (
|
||||
<button
|
||||
key={item.key}
|
||||
type="button"
|
||||
className={item.key === activeWorkspace ? 'command-chip command-chip-active' : 'command-chip'}
|
||||
onClick={() => setActiveWorkspace(item.key)}
|
||||
aria-pressed={item.key === activeWorkspace}
|
||||
aria-label={`Ga naar ${item.label}`}
|
||||
>
|
||||
{item.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<span>{selectedProject ? `Actief bereik: ${projectContextLabel}` : 'De regionale gegevens worden ingeladen.'}</span>
|
||||
</div>
|
||||
|
||||
{activeWorkspace === 'overview' ? (
|
||||
<OverviewWorkspace
|
||||
selectedProject={selectedProject}
|
||||
@@ -1330,6 +1298,8 @@ function App(): JSX.Element {
|
||||
/>
|
||||
</aside>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user