@metastringfoundation/map-list 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/components/Handler/LayerCompareControl.d.ts +7 -0
  2. package/dist/components/Handler/LayerCompareControl.d.ts.map +1 -0
  3. package/dist/components/Handler/LayerCompareControl.js +18 -0
  4. package/dist/components/Handler/MapComparisonControl.d.ts +7 -0
  5. package/dist/components/Handler/MapComparisonControl.d.ts.map +1 -0
  6. package/dist/components/Handler/MapComparisonControl.js +8 -0
  7. package/dist/components/core/button.js +1 -1
  8. package/dist/components/core/input.d.ts.map +1 -1
  9. package/dist/components/core/input.js +1 -1
  10. package/dist/components/dualMap/MapLayerCard.d.ts +8 -0
  11. package/dist/components/dualMap/MapLayerCard.d.ts.map +1 -0
  12. package/dist/components/dualMap/MapLayerCard.js +68 -0
  13. package/dist/components/dualMap/index.d.ts +3 -0
  14. package/dist/components/dualMap/index.d.ts.map +1 -0
  15. package/dist/components/dualMap/index.js +277 -0
  16. package/dist/components/map/compare-sidebar.d.ts +2 -0
  17. package/dist/components/map/compare-sidebar.d.ts.map +1 -0
  18. package/dist/components/map/compare-sidebar.js +34 -0
  19. package/dist/components/map/compare.d.ts +2 -0
  20. package/dist/components/map/compare.d.ts.map +1 -0
  21. package/dist/components/map/compare.js +42 -0
  22. package/dist/components/map/index.d.ts.map +1 -1
  23. package/dist/components/map/index.js +14 -1
  24. package/dist/components/map/layers/grid/index.d.ts.map +1 -1
  25. package/dist/components/map/layers/grid/index.js +11 -1
  26. package/dist/components/map/layers/index.d.ts.map +1 -1
  27. package/dist/components/map/layers/index.js +17 -14
  28. package/dist/components/map/layers/raster/index.d.ts.map +1 -1
  29. package/dist/components/map/layers/raster/index.js +8 -8
  30. package/dist/components/map/layers/vector/index.d.ts.map +1 -1
  31. package/dist/components/map/layers/vector/index.js +25 -1
  32. package/dist/components/map/search.d.ts +2 -0
  33. package/dist/components/map/search.d.ts.map +1 -0
  34. package/dist/components/map/search.js +122 -0
  35. package/dist/components/map/split-map/SplitMapComparision.d.ts +2 -0
  36. package/dist/components/map/split-map/SplitMapComparision.d.ts.map +1 -0
  37. package/dist/components/map/split-map/SplitMapComparision.js +78 -0
  38. package/dist/components/map-comparison/attribute-selector.d.ts +11 -0
  39. package/dist/components/map-comparison/attribute-selector.d.ts.map +1 -0
  40. package/dist/components/map-comparison/attribute-selector.js +10 -0
  41. package/dist/components/map-comparison/comparison-panel.d.ts +2 -0
  42. package/dist/components/map-comparison/comparison-panel.d.ts.map +1 -0
  43. package/dist/components/map-comparison/comparison-panel.js +45 -0
  44. package/dist/components/map-comparison/comparison-stats.d.ts +2 -0
  45. package/dist/components/map-comparison/comparison-stats.d.ts.map +1 -0
  46. package/dist/components/map-comparison/comparison-stats.js +35 -0
  47. package/dist/components/map-comparison/comparison-view.d.ts +2 -0
  48. package/dist/components/map-comparison/comparison-view.d.ts.map +1 -0
  49. package/dist/components/map-comparison/comparison-view.js +152 -0
  50. package/dist/components/map-comparison/comparison-wrapper.d.ts +8 -0
  51. package/dist/components/map-comparison/comparison-wrapper.d.ts.map +1 -0
  52. package/dist/components/map-comparison/comparison-wrapper.js +26 -0
  53. package/dist/components/map-comparison/index.d.ts +3 -0
  54. package/dist/components/map-comparison/index.d.ts.map +1 -0
  55. package/dist/components/map-comparison/index.js +165 -0
  56. package/dist/components/map-comparison/types.d.ts +30 -0
  57. package/dist/components/map-comparison/types.d.ts.map +1 -0
  58. package/dist/components/map-comparison/types.js +2 -0
  59. package/dist/components/map-comparison/use-map-comparison.d.ts +18 -0
  60. package/dist/components/map-comparison/use-map-comparison.d.ts.map +1 -0
  61. package/dist/components/map-comparison/use-map-comparison.js +139 -0
  62. package/dist/components/sidebar/common/attribute-compare-addon.d.ts +7 -0
  63. package/dist/components/sidebar/common/attribute-compare-addon.d.ts.map +1 -0
  64. package/dist/components/sidebar/common/attribute-compare-addon.js +36 -0
  65. package/dist/components/sidebar/common/layer-compare-addon.d.ts +4 -0
  66. package/dist/components/sidebar/common/layer-compare-addon.d.ts.map +1 -0
  67. package/dist/components/sidebar/common/layer-compare-addon.js +17 -0
  68. package/dist/components/sidebar/common/layer-item-style.d.ts.map +1 -1
  69. package/dist/components/sidebar/common/layer-item-style.js +46 -1
  70. package/dist/components/sidebar/common/layer-item.d.ts.map +1 -1
  71. package/dist/components/sidebar/common/layer-item.js +1 -1
  72. package/dist/components/sidebar/common/opacity-handler-addon.d.ts +5 -2
  73. package/dist/components/sidebar/common/opacity-handler-addon.d.ts.map +1 -1
  74. package/dist/components/sidebar/common/opacity-handler-addon.js +101 -4
  75. package/dist/components/sidebar/common/style-legend.d.ts.map +1 -1
  76. package/dist/components/sidebar/common/style-legend.js +1 -2
  77. package/dist/components/sidebar/comparison/index.d.ts +4 -0
  78. package/dist/components/sidebar/comparison/index.d.ts.map +1 -0
  79. package/dist/components/sidebar/comparison/index.js +34 -0
  80. package/dist/components/sidebar/index.d.ts.map +1 -1
  81. package/dist/components/sidebar/search/attribute-comparison.d.ts +10 -0
  82. package/dist/components/sidebar/search/attribute-comparison.d.ts.map +1 -0
  83. package/dist/components/sidebar/search/attribute-comparison.js +137 -0
  84. package/dist/components/sidebar/search/index.d.ts +2 -0
  85. package/dist/components/sidebar/search/index.d.ts.map +1 -0
  86. package/dist/components/sidebar/search/index.js +29 -0
  87. package/dist/components/sidebar/selected/index.d.ts.map +1 -1
  88. package/dist/components/sidebar/selected/index.js +7 -4
  89. package/dist/components/sidebar/tabs.js +2 -2
  90. package/dist/hooks/use-layers.d.ts +10 -0
  91. package/dist/hooks/use-layers.d.ts.map +1 -1
  92. package/dist/hooks/use-layers.js +115 -5
  93. package/dist/hooks/use-polygon-data.d.ts +34 -0
  94. package/dist/hooks/use-polygon-data.d.ts.map +1 -0
  95. package/dist/hooks/use-polygon-data.js +74 -0
  96. package/dist/index.css +708 -28
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +10 -1
  99. package/dist/services/naksha.d.ts.map +1 -1
  100. package/dist/services/naksha.js +22 -158
  101. package/dist/services/polygon.d.ts +36 -0
  102. package/dist/services/polygon.d.ts.map +1 -0
  103. package/dist/services/polygon.js +67 -0
  104. package/dist/utils/naksha.d.ts.map +1 -1
  105. package/dist/utils/naksha.js +15 -6
  106. package/package.json +16 -15
@@ -0,0 +1,152 @@
1
+ "use client";
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.default = ComparisonView;
41
+ const jsx_runtime_1 = require("react/jsx-runtime");
42
+ const react_1 = require("react");
43
+ const maplibre_1 = __importStar(require("react-map-gl/maplibre"));
44
+ const map_common_1 = require("@metastringfoundation/map-common");
45
+ const use_map_comparison_1 = require("./use-map-comparison");
46
+ const layers_1 = require("../map/layers");
47
+ const popup_1 = __importDefault(require("../map/popup"));
48
+ const use_layers_1 = __importDefault(require("../../hooks/use-layers"));
49
+ const comparison_stats_1 = __importDefault(require("./comparison-stats"));
50
+ const NavControl = maplibre_1.NavigationControl;
51
+ function ComparisonView() {
52
+ const { config } = (0, use_map_comparison_1.useMapComparison)();
53
+ const { mp, layer } = (0, use_layers_1.default)();
54
+ const [coordsByPane, setCoordsByPane] = (0, react_1.useState)({});
55
+ const [viewStates, setViewStates] = (0, react_1.useState)({});
56
+ const initialViewState = (0, react_1.useMemo)(() => mp.defaultViewState ?? map_common_1.defaultViewState, [mp.defaultViewState]);
57
+ // Initialize view states
58
+ (0, react_1.useEffect)(() => {
59
+ if (config.layers.length > 0) {
60
+ const newViewStates = {};
61
+ config.layers.forEach((compLayer) => {
62
+ if (!viewStates[compLayer.layerId]) {
63
+ newViewStates[compLayer.layerId] = initialViewState;
64
+ }
65
+ });
66
+ if (Object.keys(newViewStates).length > 0) {
67
+ setViewStates((prev) => ({ ...prev, ...newViewStates }));
68
+ }
69
+ }
70
+ }, [config.layers, initialViewState]);
71
+ // Sync view states if enabled
72
+ const handleViewStateChange = (layerId, viewState) => {
73
+ if (config.syncView && config.layers.length > 1) {
74
+ // Sync all maps to the same view state
75
+ const syncedViewStates = {};
76
+ config.layers.forEach((l) => {
77
+ syncedViewStates[l.layerId] = viewState;
78
+ });
79
+ setViewStates((prev) => ({ ...prev, ...syncedViewStates }));
80
+ }
81
+ else {
82
+ // Update only the specific map
83
+ setViewStates((prev) => ({ ...prev, [layerId]: viewState }));
84
+ }
85
+ };
86
+ const onMouseMove = (layerId) => (e) => {
87
+ if (!e.lngLat)
88
+ return;
89
+ setCoordsByPane((prev) => ({
90
+ ...prev,
91
+ [layerId]: e.lngLat,
92
+ }));
93
+ };
94
+ if (config.layers.length === 0) {
95
+ return ((0, jsx_runtime_1.jsx)("div", { className: "w-full h-screen flex items-center justify-center bg-gray-100", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-500 text-lg mb-2", children: "No layers selected for comparison" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-400 text-sm", children: "Add layers from the comparison panel to get started" })] }) }));
96
+ }
97
+ // Prepare layers with attribute/style modifications
98
+ const preparedLayers = (0, react_1.useMemo)(() => {
99
+ return config.layers.map((compLayer) => {
100
+ const baseLayer = { ...compLayer.layer };
101
+ // If attribute-based comparison, modify the layer to show specific attribute
102
+ if (compLayer.attributeKey && compLayer.attributeKey.startsWith("style_")) {
103
+ const styleIndex = parseInt(compLayer.attributeKey.replace("style_", ""));
104
+ if (baseLayer.data) {
105
+ baseLayer.data = {
106
+ ...baseLayer.data,
107
+ styleIndex: styleIndex,
108
+ };
109
+ }
110
+ }
111
+ return {
112
+ ...baseLayer,
113
+ id: `compare-${compLayer.layerId}`,
114
+ };
115
+ });
116
+ }, [config.layers]);
117
+ // Render based on mode
118
+ if (config.mode === "overlay") {
119
+ // Overlay mode: stack all layers on a single map
120
+ const overlayViewState = viewStates[config.layers[0]?.layerId] || initialViewState;
121
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [config.showStats && (0, jsx_runtime_1.jsx)(comparison_stats_1.default, {}), (0, jsx_runtime_1.jsxs)(maplibre_1.default, { id: "comparison-overlay", initialViewState: overlayViewState, style: { width: "100%", height: "100%" }, mapStyle: layer.mapStyle, onMove: (e) => {
122
+ if (config.layers[0]) {
123
+ handleViewStateChange(config.layers[0].layerId, e.viewState);
124
+ }
125
+ }, children: [(0, jsx_runtime_1.jsx)(NavControl, { position: "top-right", showZoom: true, showCompass: true }), preparedLayers.map((l, index) => {
126
+ const beforeId = index > 0 ? preparedLayers[index - 1].id : undefined;
127
+ return (0, jsx_runtime_1.jsx)(layers_1.MapLayer, { layer: l, beforeId: beforeId }, l.id);
128
+ }), (0, jsx_runtime_1.jsx)(popup_1.default, { coordinates: coordsByPane["overlay"] })] })] }));
129
+ }
130
+ // Side-by-side or attribute mode: show multiple maps
131
+ const layout = (0, react_1.useMemo)(() => {
132
+ const count = config.layers.length;
133
+ if (count === 1)
134
+ return { cols: 1, rows: 1 };
135
+ if (count === 2)
136
+ return { cols: 2, rows: 1 };
137
+ if (count === 3)
138
+ return { cols: 2, rows: 2 };
139
+ return { cols: 2, rows: Math.ceil(count / 2) };
140
+ }, [config.layers.length]);
141
+ const renderMap = (compLayer, index) => {
142
+ const preparedLayer = preparedLayers[index];
143
+ const viewState = viewStates[compLayer.layerId] || initialViewState;
144
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "relative w-full h-full", children: [(0, jsx_runtime_1.jsxs)("div", { className: "absolute top-2 left-2 z-10 bg-black/70 text-white px-3 py-1 rounded-md text-sm font-medium", children: [compLayer.layer.title, compLayer.attributeLabel && ((0, jsx_runtime_1.jsxs)("span", { className: "ml-2 text-xs text-gray-300", children: ["(", compLayer.attributeLabel, ")"] }))] }), (0, jsx_runtime_1.jsxs)(maplibre_1.default, { id: `compare-${compLayer.layerId}`, initialViewState: viewState, style: { position: "absolute", inset: 0 }, mapStyle: layer.mapStyle, onMouseMove: onMouseMove(compLayer.layerId), onMove: (e) => handleViewStateChange(compLayer.layerId, e.viewState), children: [(0, jsx_runtime_1.jsx)(NavControl, { position: "top-right", showZoom: true, showCompass: true }), (0, jsx_runtime_1.jsx)(layers_1.MapLayer, { layer: preparedLayer }), (0, jsx_runtime_1.jsx)(popup_1.default, { coordinates: coordsByPane[compLayer.layerId] })] }, config.syncView ? `sync-${JSON.stringify(viewState)}` : compLayer.layerId)] }, compLayer.layerId));
145
+ };
146
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [config.showStats && (0, jsx_runtime_1.jsx)(comparison_stats_1.default, {}), (0, jsx_runtime_1.jsx)("div", { style: {
147
+ display: "grid",
148
+ gridTemplateColumns: `repeat(${layout.cols}, 1fr)`,
149
+ gridTemplateRows: `repeat(${layout.rows}, ${100 / layout.rows}vh)`,
150
+ height: "100vh",
151
+ }, children: config.layers.map((compLayer, index) => renderMap(compLayer, index)) })] }));
152
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Map Comparison Wrapper Component
3
+ *
4
+ * This component works within the existing LayersProvider context
5
+ * Use this when you already have MapProvider and LayersProvider set up
6
+ */
7
+ export default function ComparisonWrapper(): import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=comparison-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparison-wrapper.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/comparison-wrapper.tsx"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CAcxC"}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.default = ComparisonWrapper;
8
+ const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = require("react");
10
+ const comparison_panel_1 = __importDefault(require("./comparison-panel"));
11
+ const comparison_view_1 = __importDefault(require("./comparison-view"));
12
+ const use_map_comparison_1 = require("./use-map-comparison");
13
+ /**
14
+ * Map Comparison Wrapper Component
15
+ *
16
+ * This component works within the existing LayersProvider context
17
+ * Use this when you already have MapProvider and LayersProvider set up
18
+ */
19
+ function ComparisonWrapper() {
20
+ const { setIsOpen } = (0, use_map_comparison_1.useMapComparison)();
21
+ // Auto-open the comparison panel when comparison mode is activated
22
+ (0, react_1.useEffect)(() => {
23
+ setIsOpen(true);
24
+ }, [setIsOpen]);
25
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "w-full h-screen relative", children: [(0, jsx_runtime_1.jsx)(comparison_panel_1.default, {}), (0, jsx_runtime_1.jsx)(comparison_view_1.default, {})] }));
26
+ }
@@ -0,0 +1,3 @@
1
+ declare const MapComparison: () => import("react/jsx-runtime").JSX.Element;
2
+ export default MapComparison;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/index.tsx"],"names":[],"mappings":"AAsJA,QAAA,MAAM,aAAa,+CAoQlB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ // @ts-nocheck
8
+ const react_1 = require("react");
9
+ const use_layers_1 = __importDefault(require("../../hooks/use-layers"));
10
+ const core_1 = require("../core");
11
+ const constants_1 = require("../../static/constants");
12
+ const naksha_1 = require("../../utils/naksha");
13
+ const LayerCard = ({ layer, selectedAttributes, isLoadingAttributes, onDropdownToggle, onAttributeToggle }) => {
14
+ const [isDropdownOpen, setIsDropdownOpen] = (0, react_1.useState)(false);
15
+ const attributes = (0, react_1.useMemo)(() => {
16
+ const propertyMap = layer.data?.propertyMap || {};
17
+ return Object.entries(propertyMap).map(([key, displayName]) => ({
18
+ key,
19
+ displayName: displayName || key,
20
+ }));
21
+ }, [layer.data?.propertyMap]);
22
+ const selectedCount = selectedAttributes.size;
23
+ const totalCount = attributes.length;
24
+ const handleDropdownClick = () => {
25
+ const wasOpen = isDropdownOpen;
26
+ const newState = !isDropdownOpen;
27
+ setIsDropdownOpen(newState);
28
+ // Fetch data when opening the dropdown (was closed, now opening)
29
+ if (newState && !wasOpen) {
30
+ onDropdownToggle();
31
+ }
32
+ };
33
+ const formatDate = (dateString) => {
34
+ if (!dateString)
35
+ return null;
36
+ try {
37
+ return new Date(dateString).toLocaleDateString();
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ };
43
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-3 border-b border-gray-200 bg-white hover:bg-gray-50 transition-colors", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex gap-3 mb-3", children: [(0, jsx_runtime_1.jsx)("img", { className: "flex shrink-0 overflow-hidden h-16 w-16 object-cover border border-gray-300 rounded shadow-sm", src: layer.thumbnail || constants_1.FALLBACK_THUMB, alt: layer.title }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-semibold text-gray-900 mb-1 leading-tight truncate", title: layer.title, children: layer.title }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-600 line-clamp-2 mb-2", title: layer.description, children: layer.description || "No description available" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-sm text-gray-500", children: [layer.createdBy && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: "By:" }), (0, jsx_runtime_1.jsx)("span", { children: layer.createdBy })] })), formatDate(layer.createdDate) && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: "Date:" }), (0, jsx_runtime_1.jsx)("span", { children: formatDate(layer.createdDate) })] })), layer.license && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: "License:" }), (0, jsx_runtime_1.jsx)("span", { children: layer.license })] })), layer.tags && layer.tags.length > 0 && ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: "Tags:" }), (0, jsx_runtime_1.jsxs)("span", { children: [layer.tags.slice(0, 2).join(", "), layer.tags.length > 2 ? "..." : ""] })] }))] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-2", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: handleDropdownClick, className: "w-full flex items-center justify-between px-3 py-2 text-sm font-medium text-gray-700 bg-gray-50 hover:bg-gray-100 border border-gray-300 rounded transition-colors", children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { children: "Attributes" }), selectedCount > 0 && ((0, jsx_runtime_1.jsxs)("span", { className: "px-1.5 py-0.5 bg-green-100 text-green-700 rounded text-sm font-semibold", children: [selectedCount, "/", totalCount] }))] }), isDropdownOpen ? (0, jsx_runtime_1.jsx)(core_1.UpIcon, {}) : (0, jsx_runtime_1.jsx)(core_1.DownIcon, {})] }), isDropdownOpen && ((0, jsx_runtime_1.jsx)("div", { className: "mt-2 border border-gray-300 rounded bg-white max-h-64 overflow-y-auto shadow-sm scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-gray-100", children: isLoadingAttributes ? ((0, jsx_runtime_1.jsx)("div", { className: "px-3 py-4 text-sm text-gray-500 italic text-center", children: "Loading attributes..." })) : attributes.length > 0 ? (attributes.map((attr) => ((0, jsx_runtime_1.jsxs)("label", { className: "flex items-center gap-2 px-3 py-2 hover:bg-gray-50 cursor-pointer border-b border-gray-100 last:border-b-0 transition-colors", children: [(0, jsx_runtime_1.jsx)(core_1.CheckboxInput, { name: `${layer.id}-${attr.key}`, checked: selectedAttributes.has(attr.key), onChange: () => {
44
+ onAttributeToggle(attr.key);
45
+ }, style: { accentColor: '#16a34a' } }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-gray-700 flex-1", children: attr.displayName })] }, attr.key)))) : ((0, jsx_runtime_1.jsx)("div", { className: "px-3 py-4 text-sm text-gray-500 italic text-center", children: "No attributes available for this layer" })) }))] })] }));
46
+ };
47
+ const MapComparison = () => {
48
+ const { layer, mp } = (0, use_layers_1.default)();
49
+ const [isOpen, setIsOpen] = (0, react_1.useState)(false);
50
+ const [searchTerm, setSearchTerm] = (0, react_1.useState)("");
51
+ const [compareSelectedLayers, setCompareSelectedLayers] = (0, react_1.useState)(new Set());
52
+ const [selectedAttributes, setSelectedAttributes] = (0, react_1.useState)({});
53
+ const [loadingAttributes, setLoadingAttributes] = (0, react_1.useState)({});
54
+ const [layersWithData, setLayersWithData] = (0, react_1.useState)({});
55
+ const fetchingRef = (0, react_1.useRef)(new Set());
56
+ const toggleOpen = () => setIsOpen(!isOpen);
57
+ // Filter layers based on search term
58
+ const filteredLayers = (0, react_1.useMemo)(() => {
59
+ if (!searchTerm.trim()) {
60
+ return layer.all;
61
+ }
62
+ const term = searchTerm.toLowerCase();
63
+ return layer.all.filter((l) => {
64
+ return (l.title?.toLowerCase().includes(term) ||
65
+ l.description?.toLowerCase().includes(term) ||
66
+ l.createdBy?.toLowerCase().includes(term) ||
67
+ l.tags?.some((tag) => tag.toLowerCase().includes(term)));
68
+ });
69
+ }, [layer.all, searchTerm]);
70
+ const handleCompareToggle = (layerId) => {
71
+ setCompareSelectedLayers((prev) => {
72
+ const newSet = new Set(prev);
73
+ if (newSet.has(layerId)) {
74
+ newSet.delete(layerId);
75
+ }
76
+ else {
77
+ newSet.add(layerId);
78
+ }
79
+ return newSet;
80
+ });
81
+ };
82
+ const fetchLayerAttributes = async (layerId) => {
83
+ const layerItem = layer.all.find((l) => l.id === layerId);
84
+ if (!layerItem)
85
+ return;
86
+ // Skip if already fetched or currently loading
87
+ if (layersWithData[layerId] || fetchingRef.current.has(layerId))
88
+ return;
89
+ // If layer already has propertyMap, use it directly
90
+ if (layerItem.data?.propertyMap && Object.keys(layerItem.data.propertyMap).length > 0) {
91
+ setLayersWithData((prev) => ({
92
+ ...prev,
93
+ [layerId]: layerItem,
94
+ }));
95
+ setSelectedAttributes((prev) => ({
96
+ ...prev,
97
+ [layerId]: new Set(),
98
+ }));
99
+ return;
100
+ }
101
+ fetchingRef.current.add(layerId);
102
+ setLoadingAttributes((prev) => ({ ...prev, [layerId]: true }));
103
+ try {
104
+ const layerData = await (0, naksha_1.getLayerStyle)(layerItem, 0, // styleIndex
105
+ mp.nakshaApiEndpoint, mp.geoserver);
106
+ const updatedLayer = {
107
+ ...layerItem,
108
+ data: layerData,
109
+ };
110
+ setLayersWithData((prev) => ({
111
+ ...prev,
112
+ [layerId]: updatedLayer,
113
+ }));
114
+ setSelectedAttributes((prev) => ({
115
+ ...prev,
116
+ [layerId]: new Set(),
117
+ }));
118
+ }
119
+ catch (error) {
120
+ console.error("Error fetching layer attributes:", error);
121
+ }
122
+ finally {
123
+ fetchingRef.current.delete(layerId);
124
+ setLoadingAttributes((prev) => ({ ...prev, [layerId]: false }));
125
+ }
126
+ };
127
+ const handleAttributeToggle = (layerId, attributeKey) => {
128
+ setSelectedAttributes((prev) => {
129
+ const layerAttributes = prev[layerId] || new Set();
130
+ const newSet = new Set(layerAttributes);
131
+ if (newSet.has(attributeKey)) {
132
+ newSet.delete(attributeKey);
133
+ }
134
+ else {
135
+ newSet.add(attributeKey);
136
+ // Auto-check the main compare checkbox when any attribute is selected
137
+ if (!compareSelectedLayers.has(layerId)) {
138
+ setCompareSelectedLayers((prevCompare) => {
139
+ const newCompareSet = new Set(prevCompare);
140
+ newCompareSet.add(layerId);
141
+ return newCompareSet;
142
+ });
143
+ }
144
+ }
145
+ return {
146
+ ...prev,
147
+ [layerId]: newSet,
148
+ };
149
+ });
150
+ };
151
+ const handleCompare = () => {
152
+ // TODO: Implement comparison logic
153
+ console.log("Comparing layers:", Array.from(compareSelectedLayers));
154
+ console.log("Selected attributes:", selectedAttributes);
155
+ // This will trigger the actual comparison functionality
156
+ };
157
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("button", { onClick: toggleOpen, type: "button", className: "absolute left-4 top-[60px] z-10 bg-white rounded-lg shadow-lg flex items-center gap-2 font-medium hover:bg-gray-50 transition-colors border border-gray-200 px-4 py-3", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "18", height: "18", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", className: "text-green-600", children: [(0, jsx_runtime_1.jsx)("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "22" }), (0, jsx_runtime_1.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" })] }), (0, jsx_runtime_1.jsx)("span", { children: "Compare" })] }), isOpen && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 flex items-center justify-center z-50 p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-white rounded-lg shadow-2xl w-full max-w-3xl h-[85vh] flex flex-col overflow-hidden border border-gray-200", children: [(0, jsx_runtime_1.jsx)("div", { className: "px-6 py-4 border-b border-gray-200 bg-gray-50", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 shrink-0", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", className: "text-green-600", children: [(0, jsx_runtime_1.jsx)("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "22" }), (0, jsx_runtime_1.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" })] }), (0, jsx_runtime_1.jsx)("h2", { className: "text-xl font-semibold text-gray-800 whitespace-nowrap", children: "Map Comparison" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 flex-1 min-w-0 max-w-md", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex-1 min-w-0", children: (0, jsx_runtime_1.jsx)(core_1.SearchInput, { placeholder: "Search layers...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value) }) }), (0, jsx_runtime_1.jsx)("button", { onClick: toggleOpen, type: "button", className: "flex items-center justify-center w-8 h-8 bg-red-100 hover:bg-red-200 text-red-800 rounded transition-colors shrink-0", title: "Close", children: (0, jsx_runtime_1.jsxs)("svg", { width: "18", height: "18", fill: "none", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto bg-white", children: filteredLayers.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center h-full min-h-[400px] p-8 text-center text-gray-500", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "mb-2 text-base", children: searchTerm ? "No layers found" : "No layers available" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm", children: searchTerm
158
+ ? "Try adjusting your search terms"
159
+ : "Layers will appear here when available" })] }) })) : (filteredLayers.map((layerItem) => {
160
+ // Use fetched layer data if available, otherwise use original
161
+ const layerData = layersWithData[layerItem.id] || layerItem;
162
+ return ((0, jsx_runtime_1.jsx)(LayerCard, { layer: layerData, isLoadingAttributes: loadingAttributes[layerItem.id] || false, selectedAttributes: selectedAttributes[layerItem.id] || new Set(), onDropdownToggle: () => fetchLayerAttributes(layerItem.id), onAttributeToggle: (attributeKey) => handleAttributeToggle(layerItem.id, attributeKey) }, layerItem.id));
163
+ })) }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-gray-200 bg-gray-50", children: (0, jsx_runtime_1.jsx)("button", { onClick: handleCompare, type: "button", className: "px-5 py-2.5 text-white bg-green-600 hover:bg-green-700 rounded-md transition-colors font-medium text-sm shadow-sm", children: "Compare" }) })] }) }))] }));
164
+ };
165
+ exports.default = MapComparison;
@@ -0,0 +1,30 @@
1
+ import { GeoserverLayer } from "../../interfaces";
2
+ export type ComparisonMode = "side-by-side" | "overlay" | "attribute";
3
+ export interface ComparisonLayer {
4
+ layerId: string;
5
+ layer: GeoserverLayer;
6
+ attributeKey?: string;
7
+ attributeLabel?: string;
8
+ styleIndex?: number;
9
+ }
10
+ export interface ComparisonConfig {
11
+ mode: ComparisonMode;
12
+ layers: ComparisonLayer[];
13
+ syncView: boolean;
14
+ showStats: boolean;
15
+ }
16
+ export interface ComparisonStats {
17
+ layerId: string;
18
+ attributeKey?: string;
19
+ totalFeatures?: number;
20
+ minValue?: number;
21
+ maxValue?: number;
22
+ avgValue?: number;
23
+ uniqueValues?: number;
24
+ }
25
+ export interface AttributeOption {
26
+ key: string;
27
+ label: string;
28
+ type: "numeric" | "categorical" | "date";
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,cAAc,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;CAC1C"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,18 @@
1
+ import { GeoserverLayer } from "../../interfaces";
2
+ import { ComparisonConfig, ComparisonMode, AttributeOption } from "./types";
3
+ export declare function useMapComparison(): {
4
+ isOpen: boolean;
5
+ setIsOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
6
+ config: ComparisonConfig;
7
+ availableLayers: GeoserverLayer[];
8
+ getLayerAttributes: (layerId: string) => AttributeOption[];
9
+ addLayer: (layerId: string, attributeKey?: string, styleIndex?: number) => void;
10
+ removeLayer: (layerId: string) => void;
11
+ updateLayerAttribute: (layerId: string, attributeKey?: string, styleIndex?: number) => void;
12
+ setMode: (mode: ComparisonMode) => void;
13
+ toggleSyncView: () => void;
14
+ toggleStats: () => void;
15
+ clearComparison: () => void;
16
+ isLayerInComparison: (layerId: string) => boolean;
17
+ };
18
+ //# sourceMappingURL=use-map-comparison.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-map-comparison.d.ts","sourceRoot":"","sources":["../../../src/components/map-comparison/use-map-comparison.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EACL,gBAAgB,EAEhB,cAAc,EACd,eAAe,EAChB,MAAM,SAAS,CAAC;AAGjB,wBAAgB,gBAAgB;;;;;kCAiBlB,MAAM,KAAG,eAAe,EAAE;wBAqCzB,MAAM,iBACA,MAAM,eACR,MAAM;2BA2BmB,MAAM;oCASpC,MAAM,iBAAiB,MAAM,eAAe,MAAM;oBA0B3B,cAAc;;;;mCA0BrC,MAAM;EAqBnB"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.useMapComparison = useMapComparison;
7
+ const react_1 = require("react");
8
+ const use_layers_1 = __importDefault(require("../../hooks/use-layers"));
9
+ function useMapComparison() {
10
+ const { layer } = (0, use_layers_1.default)();
11
+ const [isOpen, setIsOpen] = (0, react_1.useState)(false);
12
+ const [config, setConfig] = (0, react_1.useState)({
13
+ mode: "side-by-side",
14
+ layers: [],
15
+ syncView: true,
16
+ showStats: false,
17
+ });
18
+ // Get available layers
19
+ const availableLayers = (0, react_1.useMemo)(() => {
20
+ return layer.all || [];
21
+ }, [layer.all]);
22
+ // Get available attributes for a layer
23
+ const getLayerAttributes = (0, react_1.useCallback)((layerId) => {
24
+ const layerData = availableLayers.find((l) => l.id === layerId);
25
+ if (!layerData?.data?.propertyMap)
26
+ return [];
27
+ const attributes = [];
28
+ const propertyMap = layerData.data.propertyMap;
29
+ // Add all properties from propertyMap
30
+ Object.entries(propertyMap).forEach(([key, label]) => {
31
+ attributes.push({
32
+ key,
33
+ label: String(label),
34
+ type: "categorical", // Default, can be enhanced with actual type detection
35
+ });
36
+ });
37
+ // Add style-based attributes if available
38
+ if (layerData.data.styles && layerData.data.styles.length > 0) {
39
+ layerData.data.styles.forEach((style, index) => {
40
+ if (style.styleName) {
41
+ attributes.push({
42
+ key: `style_${index}`,
43
+ label: style.styleTitle || style.styleName,
44
+ type: "categorical",
45
+ });
46
+ }
47
+ });
48
+ }
49
+ return attributes;
50
+ }, [availableLayers]);
51
+ // Add layer to comparison
52
+ const addLayer = (0, react_1.useCallback)((layerId, attributeKey, styleIndex) => {
53
+ const layerData = availableLayers.find((l) => l.id === layerId);
54
+ if (!layerData)
55
+ return;
56
+ const attributeLabel = attributeKey
57
+ ? getLayerAttributes(layerId).find((attr) => attr.key === attributeKey)
58
+ ?.label || attributeKey
59
+ : undefined;
60
+ const newLayer = {
61
+ layerId,
62
+ layer: layerData,
63
+ attributeKey,
64
+ attributeLabel,
65
+ styleIndex,
66
+ };
67
+ setConfig((prev) => ({
68
+ ...prev,
69
+ layers: [...prev.layers, newLayer],
70
+ }));
71
+ }, [availableLayers, getLayerAttributes]);
72
+ // Remove layer from comparison
73
+ const removeLayer = (0, react_1.useCallback)((layerId) => {
74
+ setConfig((prev) => ({
75
+ ...prev,
76
+ layers: prev.layers.filter((l) => l.layerId !== layerId),
77
+ }));
78
+ }, []);
79
+ // Update layer attribute
80
+ const updateLayerAttribute = (0, react_1.useCallback)((layerId, attributeKey, styleIndex) => {
81
+ setConfig((prev) => ({
82
+ ...prev,
83
+ layers: prev.layers.map((l) => {
84
+ if (l.layerId === layerId) {
85
+ const attributeLabel = attributeKey
86
+ ? getLayerAttributes(layerId).find((attr) => attr.key === attributeKey)?.label || attributeKey
87
+ : undefined;
88
+ return {
89
+ ...l,
90
+ attributeKey,
91
+ attributeLabel,
92
+ styleIndex,
93
+ };
94
+ }
95
+ return l;
96
+ }),
97
+ }));
98
+ }, [getLayerAttributes]);
99
+ // Set comparison mode
100
+ const setMode = (0, react_1.useCallback)((mode) => {
101
+ setConfig((prev) => ({ ...prev, mode }));
102
+ }, []);
103
+ // Toggle sync view
104
+ const toggleSyncView = (0, react_1.useCallback)(() => {
105
+ setConfig((prev) => ({ ...prev, syncView: !prev.syncView }));
106
+ }, []);
107
+ // Toggle stats
108
+ const toggleStats = (0, react_1.useCallback)(() => {
109
+ setConfig((prev) => ({ ...prev, showStats: !prev.showStats }));
110
+ }, []);
111
+ // Clear all comparisons
112
+ const clearComparison = (0, react_1.useCallback)(() => {
113
+ setConfig({
114
+ mode: "side-by-side",
115
+ layers: [],
116
+ syncView: true,
117
+ showStats: false,
118
+ });
119
+ }, []);
120
+ // Check if layer is in comparison
121
+ const isLayerInComparison = (0, react_1.useCallback)((layerId) => {
122
+ return config.layers.some((l) => l.layerId === layerId);
123
+ }, [config.layers]);
124
+ return {
125
+ isOpen,
126
+ setIsOpen,
127
+ config,
128
+ availableLayers,
129
+ getLayerAttributes,
130
+ addLayer,
131
+ removeLayer,
132
+ updateLayerAttribute,
133
+ setMode,
134
+ toggleSyncView,
135
+ toggleStats,
136
+ clearComparison,
137
+ isLayerInComparison,
138
+ };
139
+ }
@@ -0,0 +1,7 @@
1
+ import { GeoserverLayer } from "../../../interfaces";
2
+ interface AttributeCompareAddonProps {
3
+ layer: GeoserverLayer;
4
+ }
5
+ export default function AttributeCompareAddon({ layer }: AttributeCompareAddonProps): import("react/jsx-runtime").JSX.Element | null;
6
+ export {};
7
+ //# sourceMappingURL=attribute-compare-addon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-compare-addon.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/common/attribute-compare-addon.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,UAAU,0BAA0B;IAClC,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,EAAE,KAAK,EAAE,EAAE,0BAA0B,kDAyElF"}
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = AttributeCompareAddon;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ // AttributeCompareAddon.tsx - Component to compare different attributes of the same layer
9
+ const react_1 = require("react");
10
+ const use_layers_1 = __importDefault(require("../../../hooks/use-layers"));
11
+ function AttributeCompareAddon({ layer }) {
12
+ const { layer: layerContext } = (0, use_layers_1.default)();
13
+ // Get available attributes (styles) for this layer
14
+ const availableAttributes = (0, react_1.useMemo)(() => {
15
+ if (!layer.data?.styles || !Array.isArray(layer.data.styles)) {
16
+ return [];
17
+ }
18
+ return layer.data.styles.map((style, index) => ({
19
+ styleIndex: index,
20
+ attributeKey: style.styleName || `attribute_${index}`,
21
+ attributeTitle: style.styleTitle || `Attribute ${index + 1}`,
22
+ }));
23
+ }, [layer.data?.styles]);
24
+ // Don't show if layer has less than 2 attributes
25
+ if (availableAttributes.length < 2) {
26
+ return null;
27
+ }
28
+ const comparedAttributes = layerContext.getComparedAttributes(layer.id);
29
+ const handleToggleAttribute = async (attributeKey, styleIndex, checked) => {
30
+ await layerContext.setCompareAttribute(layer.id, attributeKey, styleIndex, checked);
31
+ };
32
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col gap-2 pt-2 border-t border-gray-200", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-sm font-medium text-gray-700", children: "Compare Attributes" }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col gap-2", children: availableAttributes.map((attr) => {
33
+ const isChecked = layerContext.isAttributeCompared(layer.id, attr.attributeKey, attr.styleIndex);
34
+ return ((0, jsx_runtime_1.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer select-none text-sm", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", className: "h-4 w-4 accent-blue-600", checked: isChecked, onChange: (e) => handleToggleAttribute(attr.attributeKey, attr.styleIndex, e.target.checked) }), (0, jsx_runtime_1.jsx)("span", { className: "text-gray-700", children: attr.attributeTitle })] }, `${attr.styleIndex}-${attr.attributeKey}`));
35
+ }) }), comparedAttributes.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-gray-500 mt-1", children: [comparedAttributes.length, " attribute", comparedAttributes.length > 1 ? "s" : "", " selected"] }))] }));
36
+ }
@@ -0,0 +1,4 @@
1
+ export default function LayerCompareAddon({ id }: {
2
+ id: string;
3
+ }): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=layer-compare-addon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-compare-addon.d.ts","sourceRoot":"","sources":["../../../../src/components/sidebar/common/layer-compare-addon.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,2CAqB/D"}