File size: 7,373 Bytes
25e36e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import React, { useState } from 'react';
import { Layers, X, Map as MapIcon, Mountain, Bike, Wind, Ruler, Eye, Box } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';

export function MapLayersMenu({ 
  mapStyleType, 
  setMapStyleType,
  activeLayers = [],
  setActiveLayers
}: { 
  mapStyleType?: string, 
  setMapStyleType?: (type: string) => void,
  activeLayers?: string[],
  setActiveLayers?: (layers: string[]) => void
}) {
  const [isOpen, setIsOpen] = useState(false);

  const details = [
    { id: 'traffic', label: 'Traffic', icon: <MapIcon size={20} className="text-rose-500" />, color: 'rose' },
    { id: 'cycling', label: 'Cycling', icon: <Bike size={20} className="text-emerald-500" />, color: 'emerald' },
    { id: 'terrain', label: 'Terrain', icon: <Mountain size={20} className="text-amber-600" />, color: 'amber' },
    { id: 'airquality', label: 'Air Quality', icon: <Wind size={20} className="text-cyan-500" />, color: 'cyan' },
    { id: 'measure', label: 'Measure', icon: <Ruler size={20} className="text-indigo-500" />, color: 'indigo' },
    { id: '3dbuildings', label: '3D Buildings', icon: <Box size={20} className="text-purple-500" />, color: 'purple' },
    { id: 'labels', label: 'Street Labels', icon: <Eye size={20} className="text-orange-500" />, color: 'orange' },
  ];

  const mapTypes = [
    { id: 'default', label: 'Default', icon: <MapIcon size={20} className="text-zinc-500" /> },
    { id: 'satellite', label: 'Satellite', icon: <Eye size={20} className="text-blue-500" /> },
    { id: 'terrain', label: 'Terrain', icon: <Mountain size={20} className="text-amber-600" /> },
    { id: 'cycling', label: 'Cycling', icon: <Bike size={20} className="text-emerald-500" /> },
    { id: 'navigation', label: 'Nav', icon: <MapIcon size={20} className="text-emerald-500" /> },
  ];

  const toggleLayer = (id: string) => {
    if (!setActiveLayers) return;
    if (activeLayers.includes(id)) {
      setActiveLayers(activeLayers.filter(l => l !== id));
    } else {
      setActiveLayers([...activeLayers, id]);
    }
  };

  return (
    <div className="relative">
      <button
        onClick={() => setIsOpen(!isOpen)}
        className="p-2.5 bg-white dark:bg-zinc-900 rounded-xl shadow-lg border border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-all"
        style={{ zIndex: 10001 }}
      >
        <Layers size={22} />
      </button>

      <AnimatePresence>
        {isOpen && (
          <motion.div
            initial={{ opacity: 0, scale: 0.95, y: -10 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.95, y: -10 }}
            transition={{ duration: 0.15 }}
            className="absolute top-14 right-0 w-80 bg-white dark:bg-zinc-900 rounded-2xl shadow-2xl border border-zinc-200 dark:border-zinc-700 overflow-hidden"
            style={{ zIndex: 10002 }}
          >
            <div className="p-4 border-b border-zinc-100 dark:border-zinc-800 flex items-center justify-between">
              <h3 className="font-bold text-zinc-900 dark:text-zinc-100">Map Layers</h3>
              <button 
                onClick={() => setIsOpen(false)} 
                className="p-1.5 text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-200 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-lg transition-colors"
              >
                <X size={18} />
              </button>
            </div>

            <div className="p-4 border-b border-zinc-100 dark:border-zinc-800">
              <h4 className="text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wider mb-3">Map Type</h4>
              <div className="grid grid-cols-5 gap-2">
                {mapTypes.map((type) => (
                  <button 
                    key={type.id}
                    onClick={() => setMapStyleType && setMapStyleType(type.id)}
                    className={`flex flex-col items-center gap-1.5 p-2.5 rounded-xl transition-all ${
                      mapStyleType === type.id 
                        ? 'bg-emerald-500/10 border-2 border-emerald-500' 
                        : 'bg-zinc-50 dark:bg-zinc-800 border-2 border-transparent hover:border-zinc-300 dark:hover:border-zinc-600'
                    }`}
                  >
                    {React.cloneElement(type.icon, { className: `${type.icon.props.className} ${mapStyleType === type.id ? 'text-emerald-500' : ''}` })}
                    <span className={`text-[10px] font-medium ${mapStyleType === type.id ? 'text-emerald-600 dark:text-emerald-400' : 'text-zinc-600 dark:text-zinc-400'}`}>
                      {type.label}
                    </span>
                  </button>
                ))}
              </div>
            </div>

            <div className="p-4 border-b border-zinc-100 dark:border-zinc-800">
              <h4 className="text-xs font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wider mb-3">Overlays</h4>
              <div className="grid grid-cols-4 gap-2">
                {details.map((detail) => {
                  const isActive = activeLayers.includes(detail.id);
                  return (
                    <button 
                      key={detail.id}
                      onClick={() => toggleLayer(detail.id)}
                      className={`flex flex-col items-center gap-1.5 p-2 rounded-xl transition-all ${
                        isActive 
                          ? 'bg-emerald-500/10 border-2 border-emerald-500' 
                          : 'bg-zinc-50 dark:bg-zinc-800 border-2 border-transparent hover:border-zinc-300 dark:hover:border-zinc-600'
                      }`}
                    >
                      <div className={isActive ? `text-${detail.color}-500` : ''}>
                        {detail.icon}
                      </div>
                      <span className={`text-[10px] font-medium ${isActive ? `text-${detail.color}-600 dark:text-${detail.color}-400` : 'text-zinc-500 dark:text-zinc-500'}`}>
                        {detail.label}
                      </span>
                    </button>
                  );
                })}
              </div>
            </div>

            <div className="p-4">
              <div className="bg-emerald-500/10 rounded-xl p-3">
                <p className="text-xs text-emerald-700 dark:text-emerald-400 font-medium mb-1">Active Layers</p>
                <div className="flex flex-wrap gap-1">
                  {activeLayers.length > 0 ? (
                    activeLayers.map(layer => {
                      const detail = details.find(d => d.id === layer);
                      return detail ? (
                        <span key={layer} className="inline-flex items-center gap-1 px-2 py-0.5 bg-emerald-100 dark:bg-emerald-500/20 text-emerald-700 dark:text-emerald-400 rounded-full text-[10px] font-medium">
                          {detail.label}
                        </span>
                      ) : null;
                    })
                  ) : (
                    <span className="text-[10px] text-emerald-600 dark:text-emerald-500">No layers active</span>
                  )}
                </div>
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}