Remove clutter
This commit is contained in:
parent
f794ed7300
commit
1c58dc2fe5
8 changed files with 7 additions and 89 deletions
|
|
@ -9,7 +9,7 @@ import EnumBarChart from './EnumBarChart';
|
||||||
import StackedBarChart from './StackedBarChart';
|
import StackedBarChart from './StackedBarChart';
|
||||||
import PriceHistoryChart from './PriceHistoryChart';
|
import PriceHistoryChart from './PriceHistoryChart';
|
||||||
import ExternalSearchLinks from './ExternalSearchLinks';
|
import ExternalSearchLinks from './ExternalSearchLinks';
|
||||||
import { InfoIcon, CloseIcon } from './ui/Icons';
|
import { InfoIcon, CloseIcon } from './ui/icons';
|
||||||
import { IconButton } from './ui/IconButton';
|
import { IconButton } from './ui/IconButton';
|
||||||
import { FeatureInfoPopup } from './FeatureInfoPopup';
|
import { FeatureInfoPopup } from './FeatureInfoPopup';
|
||||||
import { EmptyState } from './ui/EmptyState';
|
import { EmptyState } from './ui/EmptyState';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
import type { FeatureMeta } from '../types';
|
import type { FeatureMeta } from '../types';
|
||||||
import { EyeIcon, InfoIcon, PlusIcon, CloseIcon } from './ui/Icons';
|
import { EyeIcon, InfoIcon, PlusIcon, CloseIcon } from './ui/icons';
|
||||||
import { IconButton } from './ui/IconButton';
|
import { IconButton } from './ui/IconButton';
|
||||||
|
|
||||||
// Re-export icons for backwards compatibility
|
|
||||||
export { EyeIcon, InfoIcon, CloseIcon as RemoveIcon } from './ui/Icons';
|
|
||||||
|
|
||||||
interface FeatureActionsProps {
|
interface FeatureActionsProps {
|
||||||
feature: FeatureMeta;
|
feature: FeatureMeta;
|
||||||
isPinned: boolean;
|
isPinned: boolean;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ import { memo, useState, useRef, useCallback, useMemo, useEffect } from 'react';
|
||||||
import { Slider } from './ui/Slider';
|
import { Slider } from './ui/Slider';
|
||||||
import { Label } from './ui/Label';
|
import { Label } from './ui/Label';
|
||||||
import { SearchInput } from './ui/SearchInput';
|
import { SearchInput } from './ui/SearchInput';
|
||||||
import { SelectionButtons } from './ui/SelectionButtons';
|
import { FilterIcon, LightbulbIcon } from './ui/icons';
|
||||||
import { FilterIcon, LightbulbIcon } from './ui/Icons';
|
|
||||||
import { EmptyState } from './ui/EmptyState';
|
import { EmptyState } from './ui/EmptyState';
|
||||||
import type { FeatureMeta, FeatureFilters } from '../types';
|
import type { FeatureMeta, FeatureFilters } from '../types';
|
||||||
import { formatFilterValue } from '../lib/format';
|
import { formatFilterValue } from '../lib/format';
|
||||||
|
|
@ -242,11 +241,7 @@ export default memo(function Filters({
|
||||||
onRemove={onRemoveFilter}
|
onRemove={onRemoveFilter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SelectionButtons
|
|
||||||
onSelectAll={() => onFilterChange(feature.name, [...allValues])}
|
|
||||||
onSelectNone={() => onFilterChange(feature.name, [])}
|
|
||||||
className="mb-1"
|
|
||||||
/>
|
|
||||||
<div className="space-y-0.5 max-h-40 overflow-y-auto">
|
<div className="space-y-0.5 max-h-40 overflow-y-auto">
|
||||||
{allValues.map((val) => (
|
{allValues.map((val) => (
|
||||||
<label
|
<label
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useRef, useCallback, type ReactNode } from 'react';
|
import { useRef, useCallback, type ReactNode } from 'react';
|
||||||
import { useClickOutside } from '../hooks/useClickOutside';
|
import { useClickOutside } from '../hooks/useClickOutside';
|
||||||
import { CloseIcon } from './ui/Icons';
|
import { CloseIcon } from './ui/icons';
|
||||||
import { IconButton } from './ui/IconButton';
|
import { IconButton } from './ui/IconButton';
|
||||||
|
|
||||||
interface InfoPopupProps {
|
interface InfoPopupProps {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,7 @@ import type { POICategoryGroup } from '../types';
|
||||||
import { useClickOutside } from '../hooks/useClickOutside';
|
import { useClickOutside } from '../hooks/useClickOutside';
|
||||||
import InfoPopup from './InfoPopup';
|
import InfoPopup from './InfoPopup';
|
||||||
import { SearchInput } from './ui/SearchInput';
|
import { SearchInput } from './ui/SearchInput';
|
||||||
import { SelectionButtons } from './ui/SelectionButtons';
|
import { InfoIcon, ChevronIcon } from './ui/icons';
|
||||||
import { InfoIcon, ChevronIcon } from './ui/Icons';
|
|
||||||
import { IconButton } from './ui/IconButton';
|
import { IconButton } from './ui/IconButton';
|
||||||
|
|
||||||
interface POIPaneProps {
|
interface POIPaneProps {
|
||||||
|
|
@ -147,9 +146,6 @@ export default function POIPane({
|
||||||
|
|
||||||
{dropdownOpen && (
|
{dropdownOpen && (
|
||||||
<div className="border border-warm-300 dark:border-navy-700 rounded shadow-lg bg-white dark:bg-navy-800">
|
<div className="border border-warm-300 dark:border-navy-700 rounded shadow-lg bg-white dark:bg-navy-800">
|
||||||
<div className="px-3 py-2 border-b border-warm-200 dark:border-navy-700">
|
|
||||||
<SelectionButtons onSelectAll={selectAll} onSelectNone={selectNone} className="text-xs" />
|
|
||||||
</div>
|
|
||||||
<div className="px-3 py-2 border-b border-warm-200 dark:border-navy-700">
|
<div className="px-3 py-2 border-b border-warm-200 dark:border-navy-700">
|
||||||
<SearchInput
|
<SearchInput
|
||||||
value={searchTerm}
|
value={searchTerm}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@ import { formatDuration, formatAge, formatNumber } from '../lib/format';
|
||||||
import { getNum } from '../lib/property-fields';
|
import { getNum } from '../lib/property-fields';
|
||||||
import InfoPopup from './InfoPopup';
|
import InfoPopup from './InfoPopup';
|
||||||
import { SearchInput } from './ui/SearchInput';
|
import { SearchInput } from './ui/SearchInput';
|
||||||
import { PaneHeader } from './ui/PaneHeader';
|
|
||||||
import { EmptyState } from './ui/EmptyState';
|
import { EmptyState } from './ui/EmptyState';
|
||||||
import { InfoIcon } from './ui/Icons';
|
import { InfoIcon } from './ui/icons';
|
||||||
|
|
||||||
interface PropertiesPaneProps {
|
interface PropertiesPaneProps {
|
||||||
properties: Property[];
|
properties: Property[];
|
||||||
|
|
@ -67,16 +66,6 @@ export function PropertiesPane({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<PaneHeader
|
|
||||||
title="Properties"
|
|
||||||
subtitle={
|
|
||||||
search.trim()
|
|
||||||
? `${filteredAndSorted.length} match${filteredAndSorted.length !== 1 ? 'es' : ''} in ${properties.length} loaded`
|
|
||||||
: `Showing ${properties.length} of ${total} properties`
|
|
||||||
}
|
|
||||||
onClose={onClose}
|
|
||||||
onInfoClick={() => setShowInfo(true)}
|
|
||||||
/>
|
|
||||||
{showInfo && (
|
{showInfo && (
|
||||||
<InfoPopup
|
<InfoPopup
|
||||||
title="Property Data"
|
title="Property Data"
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import type { ReactNode } from 'react';
|
|
||||||
import { CloseIcon, InfoIcon } from './Icons';
|
|
||||||
import { IconButton } from './IconButton';
|
|
||||||
|
|
||||||
interface PaneHeaderProps {
|
|
||||||
title: string;
|
|
||||||
subtitle?: ReactNode;
|
|
||||||
onClose?: () => void;
|
|
||||||
onInfoClick?: () => void;
|
|
||||||
children?: ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PaneHeader({ title, subtitle, onClose, onInfoClick, children }: PaneHeaderProps) {
|
|
||||||
return (
|
|
||||||
<div className="p-3 border-b border-warm-200 dark:border-navy-700">
|
|
||||||
<div className="flex justify-between items-center">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<h2 className="text-sm font-semibold dark:text-warm-100">{title}</h2>
|
|
||||||
{onInfoClick && (
|
|
||||||
<IconButton onClick={onInfoClick} title="Data source info">
|
|
||||||
<InfoIcon />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{onClose && (
|
|
||||||
<IconButton onClick={onClose} title="Close">
|
|
||||||
<CloseIcon />
|
|
||||||
</IconButton>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{subtitle && <div className="text-sm text-warm-600 dark:text-warm-400 mt-1">{subtitle}</div>}
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
interface SelectionButtonsProps {
|
|
||||||
onSelectAll: () => void;
|
|
||||||
onSelectNone: () => void;
|
|
||||||
className?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectionButtons({ onSelectAll, onSelectNone, className = '' }: SelectionButtonsProps) {
|
|
||||||
return (
|
|
||||||
<div className={`flex gap-2 text-sm ${className}`}>
|
|
||||||
<button
|
|
||||||
className="text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300 hover:underline"
|
|
||||||
onClick={onSelectAll}
|
|
||||||
>
|
|
||||||
All
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300 hover:underline"
|
|
||||||
onClick={onSelectNone}
|
|
||||||
>
|
|
||||||
None
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue