Added map filter indication
Added map filter indication + some more type fixes...
This commit is contained in:
@@ -6,7 +6,7 @@ interface BooleanFilter {
|
||||
key: string;
|
||||
label: string;
|
||||
type: "boolean";
|
||||
predicate: (node: Node, value: boolean) => boolean;
|
||||
predicate: (node: Protobuf.Mesh.NodeInfo, value: boolean) => boolean;
|
||||
}
|
||||
|
||||
interface RangeFilter {
|
||||
@@ -14,14 +14,14 @@ interface RangeFilter {
|
||||
label: string;
|
||||
type: "range";
|
||||
bounds: [number, number];
|
||||
predicate: (node: Node, value: [number, number]) => boolean;
|
||||
predicate: (node: Protobuf.Mesh.NodeInfo, value: [number, number]) => boolean;
|
||||
}
|
||||
|
||||
interface SearchFilter {
|
||||
key: string;
|
||||
label: string;
|
||||
type: "search";
|
||||
predicate: (node: Node, value: string) => boolean;
|
||||
predicate: (node: Protobuf.Mesh.NodeInfo, value: string) => boolean;
|
||||
}
|
||||
|
||||
export type FilterConfig = BooleanFilter | RangeFilter | SearchFilter;
|
||||
@@ -113,7 +113,7 @@ export function useNodeFilters(nodes: Protobuf.Mesh.NodeInfo[]) {
|
||||
acc[cfg.key] = false;
|
||||
break;
|
||||
case "range":
|
||||
acc[cfg.key] = cfg.bounds!;
|
||||
acc[cfg.key] = cfg.bounds;
|
||||
break;
|
||||
case "search":
|
||||
acc[cfg.key] = "";
|
||||
@@ -141,13 +141,36 @@ export function useNodeFilters(nodes: Protobuf.Mesh.NodeInfo[]) {
|
||||
const filteredNodes = useMemo(
|
||||
() =>
|
||||
nodes.filter((node) =>
|
||||
filterConfigs.every((cfg) => cfg.predicate(node, filters[cfg.key]))
|
||||
filterConfigs.every((cfg) => {
|
||||
const val = filters[cfg.key];
|
||||
switch (cfg.type) {
|
||||
case "boolean":
|
||||
if (typeof val !== "boolean") return true;
|
||||
return cfg.predicate(node, val);
|
||||
|
||||
case "range":
|
||||
if (
|
||||
!Array.isArray(val) ||
|
||||
val.length !== 2 ||
|
||||
typeof val[0] !== "number" ||
|
||||
typeof val[1] !== "number"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return cfg.predicate(node, val);
|
||||
|
||||
case "search":
|
||||
if (typeof val !== "string") return true;
|
||||
return cfg.predicate(node, val);
|
||||
}
|
||||
})
|
||||
),
|
||||
[nodes, filters],
|
||||
);
|
||||
|
||||
return {
|
||||
filters,
|
||||
defaultState,
|
||||
onFilterChange,
|
||||
resetFilters,
|
||||
filteredNodes,
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
FilterConfig,
|
||||
FilterValueMap,
|
||||
} from "@core/hooks/useNodeFilters.ts";
|
||||
import { cn } from "@core/utils/cn.ts";
|
||||
|
||||
interface FilterControlProps {
|
||||
configs: FilterConfig[];
|
||||
@@ -19,18 +20,25 @@ interface FilterControlProps {
|
||||
value: FilterValueMap[K],
|
||||
) => void;
|
||||
resetFilters: () => void;
|
||||
isDirty: boolean;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function FilterControl(
|
||||
{ configs, values, onChange, resetFilters, children }: FilterControlProps,
|
||||
{ configs, values, onChange, resetFilters, isDirty, children }:
|
||||
FilterControlProps,
|
||||
) {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="fixed bottom-17 right-2 px-1 py-1 bg-slate-100 text-slate-600 rounded shadow-md"
|
||||
className={cn(
|
||||
"fixed bottom-17 right-2 px-1 py-1 rounded shadow-md",
|
||||
isDirty
|
||||
? " text-slate-100 bg-green-600"
|
||||
: "text-slate-600 bg-slate-100",
|
||||
)}
|
||||
aria-label="Filter"
|
||||
>
|
||||
<FunnelIcon />
|
||||
|
||||
+14
-1
@@ -56,13 +56,25 @@ const MapPage = () => {
|
||||
);
|
||||
|
||||
const {
|
||||
filteredNodes,
|
||||
filters,
|
||||
defaultState,
|
||||
onFilterChange,
|
||||
resetFilters,
|
||||
filteredNodes,
|
||||
filterConfigs,
|
||||
} = useNodeFilters(validNodes);
|
||||
|
||||
const isDirty = useMemo(() => {
|
||||
return Object.keys(filters).some((key) => {
|
||||
const a = filters[key];
|
||||
const b = defaultState[key];
|
||||
// simple deep‐equal for primitives and [number,number]
|
||||
return Array.isArray(a) && Array.isArray(b)
|
||||
? a[0] !== b[0] || a[1] !== b[1]
|
||||
: a !== b;
|
||||
});
|
||||
}, [filters, defaultState]);
|
||||
|
||||
const handleMarkerClick = useCallback(
|
||||
(node: Protobuf.Mesh.NodeInfo, event: { originalEvent: MouseEvent }) => {
|
||||
event?.originalEvent?.stopPropagation();
|
||||
@@ -213,6 +225,7 @@ const MapPage = () => {
|
||||
values={filters}
|
||||
onChange={onFilterChange}
|
||||
resetFilters={resetFilters}
|
||||
isDirty={isDirty}
|
||||
/>
|
||||
</PageLayout>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user