Require explicit map analysis selection
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'
|
||||
import { BoxSelect, MapPinned, SlidersHorizontal, Trash2 } from 'lucide-react'
|
||||
import { BoxSelect, ChevronLeft, ChevronRight, MapPinned, Play, 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'
|
||||
@@ -335,60 +335,6 @@ const DATA_THEME_MAP_STYLES: Record<DataThemeId, { fill: string; line: string }>
|
||||
marine_environment: { fill: '#3475a3', line: '#1c557d' },
|
||||
}
|
||||
|
||||
function datasetAvailabilityLabel(
|
||||
dataset: DatasetCreateResponse,
|
||||
partitions: DatasetCreateResponse[] = [dataset],
|
||||
): string {
|
||||
const partitionCount = partitions.length
|
||||
const regionalSuffix = partitionCount > 1 ? ` · ${partitionCount} gemeenten` : ''
|
||||
if (dataset.dataset_type === 'raster' && ['digitaal_vlaanderen_dhmv', 'spw_terrain'].includes(dataset.source_name ?? '')) {
|
||||
const resolution = Number(dataset.source_metadata?.['analysis_resolution_m'])
|
||||
return `${Number.isFinite(resolution) ? `${resolution.toLocaleString('nl-BE')} m` : 'Raster'} hoogtegrid${regionalSuffix}`
|
||||
}
|
||||
if (dataset.dataset_type === 'raster' && dataset.source_name === 'vmm_flood_hazard') {
|
||||
const resolution = Number(dataset.source_metadata?.['analysis_resolution_m'])
|
||||
return `${Number.isFinite(resolution) ? `${resolution.toLocaleString('nl-BE')} m` : 'Raster'} overstromingsscenario${regionalSuffix}`
|
||||
}
|
||||
if (dataset.dataset_type === 'raster' && dataset.source_name === 'spw_bathymetry') {
|
||||
const resolution = Number(dataset.source_metadata?.['analysis_resolution_m'])
|
||||
const period = String(dataset.source_metadata?.['survey_period'] ?? '2019-2022')
|
||||
return `${Number.isFinite(resolution) ? `${resolution.toLocaleString('nl-BE')} m` : 'Raster'} waterbodemhoogte · ${period}`
|
||||
}
|
||||
if (dataset.source_name === 'vmm_vha_bathymetry_profiles') {
|
||||
const profiles = partitions.reduce(
|
||||
(total, item) => total + (item.feature_count ?? item.vector_summary?.feature_count ?? 0),
|
||||
0,
|
||||
)
|
||||
const documents = partitions.reduce(
|
||||
(total, item) => total + Number(item.source_metadata?.['document_count'] ?? 0),
|
||||
0,
|
||||
)
|
||||
return `${profiles.toLocaleString('nl-BE')} profielen · ${documents.toLocaleString('nl-BE')} bronbladen${regionalSuffix}`
|
||||
}
|
||||
if (dataset.dataset_type === 'raster' && dataset.source_name === 'department_omgeving_thematic_raster') {
|
||||
const resolution = Number(dataset.source_metadata?.['analysis_resolution_m'])
|
||||
const year = Number(dataset.source_metadata?.['observation_year'])
|
||||
const resolutionLabel = Number.isFinite(resolution) ? `${resolution.toLocaleString('nl-BE')} m` : 'Raster'
|
||||
return `${resolutionLabel} officiële bron${Number.isFinite(year) ? ` · ${year}` : ''}`
|
||||
}
|
||||
if (dataset.dataset_type === 'raster' && dataset.source_name === 'spw_walous_land_cover') {
|
||||
const resolution = Number(dataset.source_metadata?.['analysis_resolution_m'])
|
||||
const year = Number(dataset.source_metadata?.['observation_year'])
|
||||
const resolutionLabel = Number.isFinite(resolution) ? `${resolution.toLocaleString('nl-BE')} m` : 'Raster'
|
||||
return `${resolutionLabel} WALOUS-landbedekking${Number.isFinite(year) ? ` · ${year}` : ''}`
|
||||
}
|
||||
if (dataset.source_name === 'ngi_adminvector') {
|
||||
return `${(dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 0).toLocaleString('nl-BE')} officiële bestuursgebieden`
|
||||
}
|
||||
if (dataset.source_name === 'rbins_msp_2026') {
|
||||
return `${(dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 0).toLocaleString('nl-BE')} officiële planobjecten · 2026-2034`
|
||||
}
|
||||
if (dataset.source_name === 'rbins_marine_reporting_units') {
|
||||
return `${(dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 0).toLocaleString('nl-BE')} officiële zeegebieden`
|
||||
}
|
||||
return `${(dataset.feature_count ?? dataset.vector_summary?.feature_count ?? 0).toLocaleString('nl-BE')} objecten beschikbaar`
|
||||
}
|
||||
|
||||
function datasetSearchText(dataset: DatasetCreateResponse): string {
|
||||
return [
|
||||
dataset.name,
|
||||
@@ -894,6 +840,8 @@ export function MapWorkspace({
|
||||
const selectedDataset = availableMapDatasets.find((dataset) => dataset.id === selectedMapDatasetId) ?? null
|
||||
return themeIdForDataset(selectedDataset) ?? 'buildings'
|
||||
})
|
||||
const [selectedThemeIds, setSelectedThemeIds] = useState<DataThemeId[]>([])
|
||||
const [resultsPanelOpen, setResultsPanelOpen] = useState(false)
|
||||
const activeScopeProject = projects.find((project) => project.id === selectedProjectId) ?? null
|
||||
const activeScopeLabel = activeScopeProject ? operationalScopeProjectLabel(activeScopeProject) : 'Werkgebied'
|
||||
const selectedMapArea = areas.find((area) => area.id === selectedMapAreaId)
|
||||
@@ -1364,7 +1312,11 @@ export function MapWorkspace({
|
||||
const onDemandThemeActive = analysisMode === 'current' && Boolean(activeOnDemandMapProduct)
|
||||
const regionalOnDemandThemeActive = regionalScopeSelected && onDemandThemeActive
|
||||
const activeThemeAvailable = Boolean(activeThemeDataset) || onDemandThemeActive
|
||||
const coverageSelectionAvailable = analysisMode === 'current' && Boolean(selectedProjectId && selectedMapArea)
|
||||
|
||||
const selectedThemes = useMemo(
|
||||
() => DATA_THEMES.filter((theme) => selectedThemeIds.includes(theme.id)),
|
||||
[selectedThemeIds],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -1763,6 +1715,7 @@ export function MapWorkspace({
|
||||
setFirstSelectionCorner(null)
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
setResultsPanelOpen(false)
|
||||
setBboxSelectionMode(true)
|
||||
}
|
||||
|
||||
@@ -1775,7 +1728,9 @@ export function MapWorkspace({
|
||||
setSelectionBbox(bbox)
|
||||
setFirstSelectionCorner(null)
|
||||
setBboxSelectionMode(false)
|
||||
void analyzeSelection(bbox, areaIdForSelection(bbox))
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
setResultsPanelOpen(false)
|
||||
}
|
||||
|
||||
const runAreaExtract = () => {
|
||||
@@ -1792,6 +1747,7 @@ export function MapWorkspace({
|
||||
setBboxSelectionMode(false)
|
||||
setFirstSelectionCorner(null)
|
||||
setBboxInput(bboxToInputState(null))
|
||||
setResultsPanelOpen(false)
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
onClearMapSelectionExtract()
|
||||
@@ -1929,7 +1885,13 @@ export function MapWorkspace({
|
||||
if (!dataset && !onDemandProduct) {
|
||||
return
|
||||
}
|
||||
setSelectedThemeIds((current) => (
|
||||
current.includes(theme.id)
|
||||
? current.filter((themeId) => themeId !== theme.id)
|
||||
: [...current, theme.id]
|
||||
))
|
||||
setActiveThemeId(theme.id)
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
if (dataset) {
|
||||
onOpenDatasetInMap(dataset)
|
||||
@@ -1938,6 +1900,9 @@ export function MapWorkspace({
|
||||
|
||||
const setExplorerMode = (mode: 'current' | 'evolution') => {
|
||||
setAnalysisMode(mode)
|
||||
setSelectedThemeIds([])
|
||||
setResultsPanelOpen(false)
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
if (mode !== 'evolution' || activeTemporalSeriesGroups.length > 0) {
|
||||
return
|
||||
@@ -2029,7 +1994,7 @@ export function MapWorkspace({
|
||||
}
|
||||
const availableThemes: Array<MapThemeQuery<DataThemeId>> = []
|
||||
const resultFeatureLimit = selectionFeatureLimit(bbox)
|
||||
for (const theme of [activeTheme]) {
|
||||
for (const theme of selectedThemes) {
|
||||
const dataset = themeDatasetMap[theme.id]
|
||||
const partitioned = Boolean(
|
||||
dataset
|
||||
@@ -2078,6 +2043,10 @@ export function MapWorkspace({
|
||||
}
|
||||
|
||||
const analyzeSelection = async (bbox: VectorSelectionBBox, areaId?: string) => {
|
||||
if (analysisMode === 'current' && selectedThemes.length === 0) {
|
||||
return
|
||||
}
|
||||
setResultsPanelOpen(true)
|
||||
const requestId = mapAnalysisRequestSequence.current + 1
|
||||
mapAnalysisRequestSequence.current = requestId
|
||||
const startedAt = Date.now()
|
||||
@@ -2127,7 +2096,10 @@ export function MapWorkspace({
|
||||
const handleMapBboxSelect = (bbox: VectorSelectionBBox) => {
|
||||
setFirstSelectionCorner(null)
|
||||
setBboxSelectionMode(false)
|
||||
void analyzeSelection(bbox, areaIdForSelection(bbox))
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
setResultsPanelOpen(false)
|
||||
setSelectionBbox(bbox)
|
||||
}
|
||||
|
||||
const runQuickAoiExtract = () => {
|
||||
@@ -2304,11 +2276,11 @@ export function MapWorkspace({
|
||||
) : null}
|
||||
|
||||
<div className="geo-explorer-layout">
|
||||
<aside className="geo-theme-panel" aria-label="Datathema kiezen">
|
||||
<aside className="geo-theme-panel" aria-label="Thema’s en modellen kiezen">
|
||||
<div className="geo-panel-heading">
|
||||
<div>
|
||||
<h3>Focus op de kaart <small>optioneel</small></h3>
|
||||
<p>Dit bepaalt de zichtbare laag en hoofdmeting; Inzichten controleert ook de overige beschikbare thema’s.</p>
|
||||
<h3>Kies thema’s</h3>
|
||||
<p>Alleen uw gekozen bronnen en modellen worden geanalyseerd.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="geo-loaded-scope" aria-label="Ingeladen regiobereik">
|
||||
@@ -2328,15 +2300,13 @@ export function MapWorkspace({
|
||||
{DATA_THEMES.map((theme) => {
|
||||
const dataset = themeDatasetMap[theme.id]
|
||||
const onDemandProduct = onDemandProductMap.get(theme.id)
|
||||
const partitions = themePartitionMap[theme.id]
|
||||
const temporalGroups = themeTemporalSeriesMap[theme.id]
|
||||
const temporalGroup = temporalGroups[0]
|
||||
const evolutionAvailable = temporalGroups.some((group) => group.items.length >= 2)
|
||||
const available = !workspaceLoading && (analysisMode === 'current'
|
||||
? Boolean(dataset || (!readOnly && onDemandProduct))
|
||||
: Boolean(dataset) && evolutionAvailable)
|
||||
const active = activeThemeId === theme.id
|
||||
const temporalRange = temporalGroup ? temporalRangeLabel(temporalGroup.items) : null
|
||||
const active = selectedThemeIds.includes(theme.id)
|
||||
return (
|
||||
<button
|
||||
className={active ? 'geo-theme-option geo-theme-option-active' : 'geo-theme-option'}
|
||||
@@ -2351,32 +2321,36 @@ export function MapWorkspace({
|
||||
<strong>{theme.label}</strong>
|
||||
<small>
|
||||
{workspaceLoading
|
||||
? 'Beschikbaarheid controleren'
|
||||
? 'Controleren…'
|
||||
: analysisMode === 'evolution'
|
||||
? evolutionAvailable
|
||||
? `${temporalGroup.items.length} meetmomenten${temporalRange ? ` · ${temporalRange}` : ''}`
|
||||
? evolutionAvailable ? `${temporalGroup.items.length} meetmomenten` : 'Geen tijdreeks'
|
||||
: dataset
|
||||
? 'Alleen huidige toestand'
|
||||
: 'Bron nog niet ingeladen'
|
||||
: dataset
|
||||
? `${datasetAvailabilityLabel(dataset, partitions)}${onDemandProduct ? ' · zo nodig automatisch aangevuld' : ''}`
|
||||
: onDemandProduct
|
||||
? readOnly ? 'Niet opgenomen in deze demo' : onDemandProduct.availabilityLabel
|
||||
: 'Bron nog niet ingeladen'}
|
||||
? 'Lokaal beschikbaar'
|
||||
: onDemandProduct
|
||||
? readOnly ? 'Niet in demo' : 'Op aanvraag'
|
||||
: 'Niet beschikbaar'}
|
||||
</small>
|
||||
</span>
|
||||
<i>
|
||||
{workspaceLoading
|
||||
? 'Laden'
|
||||
: analysisMode === 'evolution'
|
||||
? evolutionAvailable ? 'Tijdreeks' : dataset ? 'Alleen huidig' : 'Ontbreekt'
|
||||
: dataset ? 'Beschikbaar' : onDemandProduct ? readOnly ? 'Niet in demo' : 'Automatisch' : 'Ontbreekt'}
|
||||
</i>
|
||||
<i>{active ? 'Gekozen' : available ? 'Kies' : '—'}</i>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="geo-theme-actions" aria-live="polite">
|
||||
<span>{selectedThemes.length === 0 ? 'Nog niets gekozen' : `${selectedThemes.length} gekozen`}</span>
|
||||
<button
|
||||
className="primary-action"
|
||||
type="button"
|
||||
disabled={!mapSelectionBbox || selectedThemes.length === 0 || themeResultsLoading || mapSelectionLoading}
|
||||
onClick={() => mapSelectionBbox && void analyzeSelection(mapSelectionBbox, areaIdForSelection(mapSelectionBbox))}
|
||||
>
|
||||
<Play aria-hidden="true" />
|
||||
Analyseer selectie
|
||||
</button>
|
||||
<small>{mapSelectionBbox ? 'Start alleen de gekozen analyses.' : 'Teken eerst een gebied.'}</small>
|
||||
</div>
|
||||
|
||||
<div className="geo-source-summary">
|
||||
<span>{analysisOverlayActive ? 'Actieve analyselaag' : analysisMode === 'evolution' ? 'Tijdreeks' : 'Actieve bron'}</span>
|
||||
<strong>
|
||||
@@ -2578,22 +2552,16 @@ export function MapWorkspace({
|
||||
<p>
|
||||
{bboxSelectionMode
|
||||
? 'Sleep nu een rechthoek op de kaart.'
|
||||
: !activeThemeAvailable
|
||||
? 'Teken een rechthoek om de databeschikbaarheid voor dit gebied te controleren.'
|
||||
: regionalRasterThemeActive
|
||||
? 'Teken een rechthoek; de juiste gemeentelijke rasters worden automatisch gecombineerd.'
|
||||
: onDemandThemeActive
|
||||
? 'Teken een rechthoek; officiële regionale kaartbronnen worden begrensd opgehaald, bewaard en hergebruikt.'
|
||||
: regionalBathymetryThemeActive
|
||||
? 'Teken een rechthoek of analyseer Vlaanderen; alleen overlappende VHA-partities worden samengevoegd.'
|
||||
: 'Sleep een rechthoek of analyseer het volledige werkgebied.'}
|
||||
: mapSelectionBbox
|
||||
? 'Gebied gekozen. Selecteer links één of meer thema’s en start de analyse.'
|
||||
: 'Teken een rechthoek of gebruik het volledige werkgebied. Er wordt nog niets automatisch geladen.'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="geo-map-actions">
|
||||
<button
|
||||
className={bboxSelectionMode ? 'primary-action geo-draw-active' : 'primary-action'}
|
||||
disabled={(!activeThemeAvailable && !coverageSelectionAvailable) || (analysisMode === 'evolution' && activeTemporalSeries.length < 2) || mapSelectionLoading || themeResultsLoading}
|
||||
disabled={!selectedProjectId || workspaceLoading || mapSelectionLoading || themeResultsLoading}
|
||||
type="button"
|
||||
onClick={startBboxSelection}
|
||||
>
|
||||
@@ -2602,17 +2570,19 @@ export function MapWorkspace({
|
||||
</button>
|
||||
<button
|
||||
className="secondary-action"
|
||||
disabled={(!activeThemeAvailable && !coverageSelectionAvailable) || regionalRasterThemeActive || regionalOnDemandThemeActive || (analysisMode === 'evolution' && activeTemporalSeries.length < 2) || !selectedAreaBbox || mapSelectionLoading || themeResultsLoading}
|
||||
disabled={!selectedAreaBbox || workspaceLoading || mapSelectionLoading || themeResultsLoading}
|
||||
type="button"
|
||||
title={
|
||||
regionalRasterThemeActive || regionalOnDemandThemeActive
|
||||
? 'Teken een begrensde rechthoek voor deze regionale analyse.'
|
||||
: undefined
|
||||
}
|
||||
onClick={() => selectedAreaBbox && void analyzeSelection(selectedAreaBbox, selectedMapArea?.id)}
|
||||
|
||||
onClick={() => {
|
||||
if (!selectedAreaBbox) return
|
||||
clearThemeInsights()
|
||||
clearTemporalComparison()
|
||||
setResultsPanelOpen(false)
|
||||
setSelectionBbox(selectedAreaBbox)
|
||||
}}
|
||||
>
|
||||
<MapPinned aria-hidden="true" />
|
||||
{regionalRasterThemeActive || regionalOnDemandThemeActive ? 'Selecteer een deelgebied' : 'Volledig werkgebied'}
|
||||
Volledig werkgebied
|
||||
</button>
|
||||
<button className="secondary-action" disabled={!mapSelectionBbox} type="button" onClick={clearAreaSelection}>
|
||||
<Trash2 aria-hidden="true" />
|
||||
@@ -2647,14 +2617,14 @@ export function MapWorkspace({
|
||||
selectionMode={bboxSelectionMode}
|
||||
hasSelection={Boolean(mapSelectionBbox)}
|
||||
sourceLoading={workspaceLoading || coverageLoading || officialMapProductsLoading}
|
||||
sourceReady={activeThemeAvailable && !workspaceLoading && !coverageLoading}
|
||||
sourceReady={selectedThemes.length > 0 && !workspaceLoading}
|
||||
processing={liveJourneyProcessing}
|
||||
validating={liveJourneyValidating}
|
||||
hasResult={liveJourneyHasResult}
|
||||
verified={liveJourneyVerified}
|
||||
error={liveJourneyError}
|
||||
selectionLabel={mapSelectionBbox ? 'Begrensde kaartselectie' : selectedMapArea?.name ?? 'Nog geen gebied geselecteerd'}
|
||||
sourceLabel={activeThemeAvailable ? activeTheme.shortLabel : 'Dekking wordt gecontroleerd'}
|
||||
sourceLabel={selectedThemes.length > 0 ? `${selectedThemes.length} gekozen` : 'Kies thema’s'}
|
||||
statusMessage={liveJourneyStatus}
|
||||
resultLabel={liveJourneyResultLabel}
|
||||
/>
|
||||
@@ -2703,16 +2673,28 @@ export function MapWorkspace({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
className={resultsPanelOpen ? 'geo-results-toggle geo-results-toggle-open' : 'geo-results-toggle'}
|
||||
type="button"
|
||||
aria-controls="geo-explorer-results"
|
||||
aria-expanded={resultsPanelOpen}
|
||||
onClick={() => setResultsPanelOpen((open) => !open)}
|
||||
>
|
||||
{resultsPanelOpen ? <ChevronRight aria-hidden="true" /> : <ChevronLeft aria-hidden="true" />}
|
||||
<span>{resultsPanelOpen ? 'Sluit inzichten' : 'Inzichten'}</span>
|
||||
</button>
|
||||
|
||||
<aside
|
||||
id="geo-explorer-results"
|
||||
className="geo-results-panel"
|
||||
className={resultsPanelOpen ? 'geo-results-panel geo-results-panel-open' : 'geo-results-panel'}
|
||||
aria-label="Gebiedsanalyse"
|
||||
aria-live="polite"
|
||||
aria-hidden={!resultsPanelOpen}
|
||||
>
|
||||
<div className="geo-panel-heading">
|
||||
<div>
|
||||
<h3>Inzichten</h3>
|
||||
<p>Gemeten resultaten en beschikbaarheid voor de volledige selectie.</p>
|
||||
<p>Resultaten van de gekozen analyses.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2781,12 +2763,17 @@ export function MapWorkspace({
|
||||
{!mapSelectionBbox ? (
|
||||
<div className="geo-results-empty">
|
||||
<strong>Nog geen gebied geselecteerd</strong>
|
||||
<p>Teken een rechthoek op de kaart. De analyse start automatisch zodra je loslaat.</p>
|
||||
<p>Teken een rechthoek, kies thema’s en start daarna de analyse.</p>
|
||||
</div>
|
||||
) : mapSelectionLoading || themeResultsLoading || temporalComparisonLoading ? (
|
||||
<div className="geo-results-loading" role="status">
|
||||
<span />
|
||||
<strong>De gekozen officiële bron wordt begrensd geladen en geanalyseerd…</strong>
|
||||
<strong>De gekozen bronnen worden begrensd geladen en geanalyseerd…</strong>
|
||||
</div>
|
||||
) : analysisMode === 'current' && themeInsights.length === 0 && !mapSelectionResult ? (
|
||||
<div className="geo-results-empty">
|
||||
<strong>Nog niet geanalyseerd</strong>
|
||||
<p>Kies één of meer thema’s en gebruik “Analyseer selectie”.</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
@@ -2895,16 +2882,17 @@ export function MapWorkspace({
|
||||
|
||||
<div className="geo-theme-results">
|
||||
<div className="geo-results-title-row">
|
||||
<h4>Gekozen thema</h4>
|
||||
<span>{activeSelectionResult ? 'Uitgelezen' : 'Geen meting'}</span>
|
||||
<h4>Gekozen thema’s</h4>
|
||||
<span>{themeResults.length}/{selectedThemes.length} uitgelezen</span>
|
||||
</div>
|
||||
{[activeTheme].flatMap((theme) => {
|
||||
{selectedThemes.flatMap((theme) => {
|
||||
const dataset = themeDatasetMap[theme.id]
|
||||
const items = themeResults.filter((result) => result.theme.id === theme.id)
|
||||
const rows = items.length > 0 ? items : [null]
|
||||
const themeSupportsCurrentSelection = selectionRelevantThemes.some((candidate) => candidate.id === theme.id)
|
||||
return rows.map((item, index) => {
|
||||
const resultDataset = item?.dataset ?? (activeThemeSupportsCurrentSelection ? dataset : undefined)
|
||||
const unavailableAtScale = !activeThemeSupportsCurrentSelection
|
||||
const resultDataset = item?.dataset ?? (themeSupportsCurrentSelection ? dataset : undefined)
|
||||
const unavailableAtScale = !themeSupportsCurrentSelection
|
||||
return (
|
||||
<div className="geo-theme-result-row" key={`${theme.id}:${resultDataset?.id ?? index}`}>
|
||||
<span className={`geo-theme-symbol geo-theme-symbol-${theme.id}`} aria-hidden="true" />
|
||||
|
||||
@@ -1647,3 +1647,178 @@ button.overview-command-card { cursor: pointer; }
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Explicit analysis selection and result drawer */
|
||||
.geo-explorer-layout,
|
||||
.workbench-shell-guest .geo-explorer-layout {
|
||||
grid-template-columns: clamp(15rem, 13vw, 18rem) minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.geo-theme-option {
|
||||
grid-template-columns: 0.55rem minmax(0, 1fr) auto;
|
||||
gap: var(--gi-space-2);
|
||||
min-width: 0;
|
||||
padding: 0.48rem 0.55rem;
|
||||
}
|
||||
|
||||
.geo-theme-option > .geo-theme-symbol {
|
||||
grid-column: 1;
|
||||
width: 0.42rem;
|
||||
}
|
||||
|
||||
.geo-theme-option > span:nth-child(2) {
|
||||
grid-column: 2;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.geo-theme-option > span:nth-child(2) > :where(strong, small) {
|
||||
overflow: hidden;
|
||||
overflow-wrap: normal;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.geo-theme-option > i {
|
||||
grid-column: 3;
|
||||
max-width: 4.25rem;
|
||||
overflow: hidden;
|
||||
justify-self: end;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.geo-theme-actions {
|
||||
display: grid;
|
||||
flex: 0 0 auto;
|
||||
gap: var(--gi-space-2);
|
||||
padding: var(--gi-space-3) var(--gi-space-4);
|
||||
border-top: 1px solid var(--gi-line);
|
||||
background: var(--gi-surface-soft);
|
||||
}
|
||||
|
||||
.geo-theme-actions > span {
|
||||
color: var(--gi-ink-700);
|
||||
font-size: var(--gi-text-2xs);
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.geo-theme-actions button {
|
||||
display: inline-flex;
|
||||
gap: var(--gi-space-2);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.geo-theme-actions button svg {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
}
|
||||
|
||||
.geo-theme-actions small {
|
||||
color: var(--gi-ink-500);
|
||||
font-size: var(--gi-text-3xs);
|
||||
}
|
||||
|
||||
.geo-results-panel {
|
||||
visibility: hidden;
|
||||
animation: none;
|
||||
pointer-events: none;
|
||||
transform: translateX(100%);
|
||||
transition: transform var(--gi-dur-3) var(--gi-ease-out), visibility 0s linear var(--gi-dur-3);
|
||||
}
|
||||
|
||||
.geo-results-panel.geo-results-panel-open {
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
transform: translateX(0);
|
||||
transition-delay: 0s;
|
||||
}
|
||||
|
||||
.geo-results-panel::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.geo-results-toggle {
|
||||
position: absolute;
|
||||
z-index: 7;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
display: inline-flex;
|
||||
gap: 0.3rem;
|
||||
align-items: center;
|
||||
min-height: 2.5rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-right: 0;
|
||||
border-radius: var(--gi-radius-md) 0 0 var(--gi-radius-md);
|
||||
padding: 0.55rem 0.7rem;
|
||||
background: var(--gi-brand-800);
|
||||
color: #fff;
|
||||
font-size: var(--gi-text-2xs);
|
||||
font-weight: 750;
|
||||
box-shadow: var(--gi-shadow-md);
|
||||
transform: translateY(-50%);
|
||||
transition: right var(--gi-dur-3) var(--gi-ease-out), background var(--gi-dur-2) var(--gi-ease);
|
||||
}
|
||||
|
||||
.geo-results-toggle:hover,
|
||||
.geo-results-toggle:focus-visible {
|
||||
background: var(--gi-brand-700);
|
||||
}
|
||||
|
||||
.geo-results-toggle-open {
|
||||
right: clamp(23rem, 25vw, 28rem);
|
||||
}
|
||||
|
||||
.geo-results-toggle svg {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 1240px) {
|
||||
.geo-results-panel {
|
||||
position: absolute;
|
||||
inset-block: 0;
|
||||
right: 0;
|
||||
width: min(28rem, calc(100% - 3rem));
|
||||
height: 100%;
|
||||
max-height: none;
|
||||
overflow-y: auto;
|
||||
border-top: 0;
|
||||
border-left: 1px solid var(--gi-line);
|
||||
box-shadow: var(--gi-shadow-lg);
|
||||
transform: translateX(100%) !important;
|
||||
}
|
||||
|
||||
.geo-results-panel.geo-results-panel-open {
|
||||
transform: translateX(0) !important;
|
||||
}
|
||||
|
||||
.geo-results-toggle-open {
|
||||
right: min(28rem, calc(100% - 3rem));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 620px) {
|
||||
.geo-theme-option > i {
|
||||
max-width: 3.75rem;
|
||||
}
|
||||
|
||||
.geo-results-toggle span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.geo-results-panel,
|
||||
.geo-results-toggle {
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
.geo-source-summary :where(strong, small) {
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
overflow-wrap: anywhere;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user