Clean up
This commit is contained in:
parent
b94cf17d75
commit
0c6d207967
41 changed files with 1809 additions and 1204 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCollapsibleGroups } from '../../hooks/useCollapsibleGroups';
|
||||
import { useTravelModes } from '../../hooks/useTravelModes';
|
||||
import { SearchInput } from '../ui/SearchInput';
|
||||
|
|
@ -15,9 +16,8 @@ import { IconButton } from '../ui/IconButton';
|
|||
import { TravelTimeInfoPopup } from '../ui/TravelTimeInfoPopup';
|
||||
import {
|
||||
TRANSPORT_MODES,
|
||||
MODE_LABELS,
|
||||
MODE_DESCRIPTIONS,
|
||||
MODE_ICONS,
|
||||
useTranslatedModes,
|
||||
type TransportMode,
|
||||
type TravelTimeEntry,
|
||||
} from '../../hooks/useTravelTime';
|
||||
|
|
@ -34,7 +34,6 @@ interface FeatureBrowserProps {
|
|||
travelTimeEntries: TravelTimeEntry[];
|
||||
onAddTravelTimeEntry: (mode: TransportMode) => void;
|
||||
isLicensed: boolean;
|
||||
onUpgradeClick?: () => void;
|
||||
}
|
||||
|
||||
export default function FeatureBrowser({
|
||||
|
|
@ -49,8 +48,9 @@ export default function FeatureBrowser({
|
|||
travelTimeEntries: _travelTimeEntries,
|
||||
onAddTravelTimeEntry,
|
||||
isLicensed,
|
||||
onUpgradeClick,
|
||||
}: FeatureBrowserProps) {
|
||||
const { t } = useTranslation();
|
||||
const modes = useTranslatedModes();
|
||||
const [search, setSearch] = useState('');
|
||||
const [infoFeature, setInfoFeature] = useState<FeatureMeta | null>(null);
|
||||
const [travelInfoMode, setTravelInfoMode] = useState<TransportMode | null>(null);
|
||||
|
|
@ -102,9 +102,13 @@ export default function FeatureBrowser({
|
|||
return (
|
||||
<>
|
||||
<div className="shrink-0 p-2 border-b border-warm-200 dark:border-navy-700">
|
||||
<SearchInput value={search} onChange={setSearch} placeholder="Search features..." />
|
||||
<SearchInput
|
||||
value={search}
|
||||
onChange={setSearch}
|
||||
placeholder={t('filters.searchFeatures')}
|
||||
/>
|
||||
</div>
|
||||
<div className="md:min-h-0 md:flex-1 md:overflow-y-auto flex flex-col">
|
||||
<div>
|
||||
{mergedGrouped.map((group) => {
|
||||
const isExpanded = isSearching || isGroupExpanded(group.name);
|
||||
return (
|
||||
|
|
@ -158,24 +162,24 @@ export default function FeatureBrowser({
|
|||
<ModeIcon className="w-4 h-4 text-teal-600 dark:text-teal-400 shrink-0" />
|
||||
<div className="min-w-0">
|
||||
<span className="text-sm font-medium text-navy-950 dark:text-warm-100">
|
||||
{MODE_LABELS[mode]}
|
||||
{modes.label(mode)}
|
||||
</span>
|
||||
<span className="text-xs text-warm-400 dark:text-warm-500 block">
|
||||
{MODE_DESCRIPTIONS[mode]}
|
||||
{modes.desc(mode)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-0.5 shrink-0">
|
||||
<IconButton
|
||||
onClick={() => setTravelInfoMode(mode)}
|
||||
title="Feature info"
|
||||
title={t('filters.featureInfo')}
|
||||
size="md"
|
||||
>
|
||||
<InfoIcon className="w-5 h-5 md:w-3.5 md:h-3.5" />
|
||||
</IconButton>
|
||||
<button
|
||||
onClick={() => onAddTravelTimeEntry(mode)}
|
||||
title={`Add ${MODE_LABELS[mode]} travel time`}
|
||||
title={t('travel.addTravelTime', { mode: modes.label(mode) })}
|
||||
className="p-1 rounded-md text-teal-600 dark:text-teal-400 bg-teal-50 dark:bg-teal-900/30 hover:bg-teal-100 dark:hover:bg-teal-800/40"
|
||||
>
|
||||
<PlusIcon className="w-5 h-5 md:w-5 md:h-5" strokeWidth={2.5} />
|
||||
|
|
@ -192,45 +196,15 @@ export default function FeatureBrowser({
|
|||
{mergedGrouped.length === 0 ? (
|
||||
<EmptyState
|
||||
icon={<FilterIcon className="w-8 h-8 text-warm-300 dark:text-warm-600" />}
|
||||
title={search ? 'No matching features' : 'All features are active'}
|
||||
description={
|
||||
search ? 'Try a different search term' : 'Remove a filter to see available features'
|
||||
}
|
||||
title={search ? t('filters.noMatchingFeatures') : t('filters.allFeaturesActive')}
|
||||
description={search ? t('filters.tryDifferentSearch') : t('filters.removeFilterHint')}
|
||||
className="px-3 py-4"
|
||||
/>
|
||||
) : isLicensed ? (
|
||||
<p className="flex-1 flex items-center justify-center px-4 py-6 text-xs text-center text-warm-400 dark:text-warm-500">
|
||||
Choose the filters that matter to you. The map updates as you go.
|
||||
{t('filters.chooseFilters')}
|
||||
</p>
|
||||
) : (
|
||||
<div className="mt-auto flex flex-col items-center px-5 pt-6 pb-0">
|
||||
<p className="text-sm text-warm-600 dark:text-warm-400 text-center leading-relaxed mb-1">
|
||||
See crime, schools, noise, broadband, and 50+ more filters across all of England.
|
||||
</p>
|
||||
<p className="text-xs text-warm-400 dark:text-warm-500 text-center mb-4">
|
||||
One-time payment, lifetime access.
|
||||
</p>
|
||||
<button
|
||||
onClick={onUpgradeClick}
|
||||
className="px-5 py-2.5 rounded-lg bg-gradient-to-r from-teal-500 to-teal-600 hover:from-teal-600 hover:to-teal-700 text-white font-medium text-sm shadow-sm hover:shadow-md"
|
||||
>
|
||||
Upgrade to full map
|
||||
</button>
|
||||
<svg
|
||||
viewBox="0 120 1600 230"
|
||||
className="w-full mt-4 block shrink-0"
|
||||
preserveAspectRatio="xMidYMax meet"
|
||||
>
|
||||
<path
|
||||
d="M0,350 C400,150 1200,150 1600,350 Z"
|
||||
className="fill-green-500 dark:fill-green-600"
|
||||
/>
|
||||
<path d="M100,350 C450,180 1150,180 1500,350 Z" fill="#000" opacity="0.08" />
|
||||
<path d="M250,350 C550,220 1050,220 1350,350 Z" fill="#000" opacity="0.06" />
|
||||
<image href="/house.png" x="735" y="110" width="130" height="120" />
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
{infoFeature && (
|
||||
<FeatureInfoPopup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue