Compare commits
12 Commits
4d2a94ffea
...
aeec307909
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aeec307909 | ||
|
|
369f29a769 | ||
|
|
d166b2468d | ||
|
|
59c8680c23 | ||
|
|
1a046f8212 | ||
|
|
e35216daf5 | ||
|
|
91ad47166f | ||
|
|
3a9b436352 | ||
|
|
7b881e80c2 | ||
|
|
cc19a0a466 | ||
|
|
f200d0bb20 | ||
|
|
75a0ab000f |
@@ -23,4 +23,4 @@ NEXT_PUBLIC_USE_MOCKS=true
|
|||||||
# z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
|
# z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
|
||||||
# basePath wird jetzt in public/config.json gepflegt
|
# basePath wird jetzt in public/config.json gepflegt
|
||||||
# App-Versionsnummer
|
# App-Versionsnummer
|
||||||
NEXT_PUBLIC_APP_VERSION=1.1.355
|
NEXT_PUBLIC_APP_VERSION=1.1.369
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ NEXT_PUBLIC_USE_MOCKS=false
|
|||||||
# basePath wird jetzt in public/config.json gepflegt
|
# basePath wird jetzt in public/config.json gepflegt
|
||||||
|
|
||||||
# App-Versionsnummer
|
# App-Versionsnummer
|
||||||
NEXT_PUBLIC_APP_VERSION=1.1.355
|
NEXT_PUBLIC_APP_VERSION=1.1.369
|
||||||
|
|||||||
32
.gitattributes
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Normalize line endings and mark binary files
|
||||||
|
|
||||||
|
# Default: let Git manage line endings
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Source files use LF in repo
|
||||||
|
*.js text eol=lf
|
||||||
|
*.jsx text eol=lf
|
||||||
|
*.ts text eol=lf
|
||||||
|
*.tsx text eol=lf
|
||||||
|
*.json text eol=lf
|
||||||
|
*.css text eol=lf
|
||||||
|
*.scss text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.svg text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
|
||||||
|
# Windows scripts keep CRLF
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
|
||||||
|
# Images and binaries
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.webp binary
|
||||||
|
*.ico binary
|
||||||
|
*.pdf binary
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
echo "🔄 Version wird automatisch erhöht (bumpVersion.js)..."
|
echo "🔄 Version wird automatisch erhöht (bumpVersion.js)..."
|
||||||
|
|
||||||
# Version automatisch erhöhen
|
# Version automatisch erhöhen
|
||||||
|
|||||||
18
components/icons/material-symbols/AlarmIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const AlarmIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="red"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M6 6.9L3.87 4.78l1.41-1.41L7.4 5.5zM13 1v3h-2V1zm7.13 3.78L18 6.9l-1.4-1.4l2.12-2.13zM4.5 10.5v2h-3v-2zm15 0h3v2h-3zM6 20h12a2 2 0 0 1 2 2H4a2 2 0 0 1 2-2m6-15a6 6 0 0 1 6 6v8H6v-8a6 6 0 0 1 6-6"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default AlarmIcon;
|
||||||
18
components/icons/material-symbols/EditIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const EditIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default EditIcon;
|
||||||
18
components/icons/material-symbols/EditOffIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const EditOffIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L18 21l-3-3m-12.728-.364A9 9 0 015.636 5.636m0 0L3 3l3 3m9.364 9.364L18 21M5.636 5.636L3 3"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default EditOffIcon;
|
||||||
18
components/icons/material-symbols/ExpandIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const ExpandIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ExpandIcon;
|
||||||
18
components/icons/material-symbols/InfoIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const InfoIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default InfoIcon;
|
||||||
19
components/icons/material-symbols/MapMarkerIcon.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const MapMarkerIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="rgb(0, 174, 239)"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25s-7.5-4.108-7.5-11.25a7.5 7.5 0 1115 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default MapMarkerIcon;
|
||||||
18
components/icons/material-symbols/MenuIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const MenuIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default MenuIcon;
|
||||||
18
components/icons/material-symbols/SearchIcon.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
const SearchIcon = ({ className = "h-8 w-8" }) => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="rgb(0, 174, 239)"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default SearchIcon;
|
||||||
@@ -6,7 +6,15 @@ import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
|
|||||||
import "leaflet-contextmenu";
|
import "leaflet-contextmenu";
|
||||||
import "leaflet.smooth_marker_bouncing";
|
import "leaflet.smooth_marker_bouncing";
|
||||||
import "react-toastify/dist/ReactToastify.css";
|
import "react-toastify/dist/ReactToastify.css";
|
||||||
import { InformationCircleIcon } from "@heroicons/react/20/solid";
|
import { Icon } from "@iconify/react";
|
||||||
|
import EditIcon from "@/components/icons/material-symbols/EditIcon";
|
||||||
|
import EditOffIcon from "@/components/icons/material-symbols/EditOffIcon";
|
||||||
|
import SearchIcon from "@/components/icons/material-symbols/SearchIcon";
|
||||||
|
import MenuIcon from "@/components/icons/material-symbols/MenuIcon";
|
||||||
|
import InfoIcon from "@/components/icons/material-symbols/InfoIcon";
|
||||||
|
import AlarmIcon from "@/components/icons/material-symbols/AlarmIcon";
|
||||||
|
import MapMarkerIcon from "@/components/icons/material-symbols/MapMarkerIcon";
|
||||||
|
import ExpandIcon from "@/components/icons/material-symbols/ExpandIcon";
|
||||||
import PoiUpdateModal from "@/components/pois/poiUpdateModal/PoiUpdateModal.js";
|
import PoiUpdateModal from "@/components/pois/poiUpdateModal/PoiUpdateModal.js";
|
||||||
import { ToastContainer, toast } from "react-toastify";
|
import { ToastContainer, toast } from "react-toastify";
|
||||||
import plusRoundIcon from "../icons/devices/overlapping/PlusRoundIcon.js";
|
import plusRoundIcon from "../icons/devices/overlapping/PlusRoundIcon.js";
|
||||||
@@ -26,6 +34,7 @@ import CoordinatePopup from "@/components/contextmenu/CoordinatePopup.js";
|
|||||||
import MapLayersControlPanel from "@/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js";
|
import MapLayersControlPanel from "@/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js";
|
||||||
import CoordinateInput from "@/components/uiWidgets/CoordinateInput.js";
|
import CoordinateInput from "@/components/uiWidgets/CoordinateInput.js";
|
||||||
import VersionInfoModal from "@/components/uiWidgets/VersionInfoModal.js";
|
import VersionInfoModal from "@/components/uiWidgets/VersionInfoModal.js";
|
||||||
|
import AreaDropdown from "@/components/uiWidgets/AreaDropdown";
|
||||||
//----------Daten aus API--------------------
|
//----------Daten aus API--------------------
|
||||||
import { fetchPoiDataService } from "@/services/database/pois/fetchPoiDataByIdService.js";
|
import { fetchPoiDataService } from "@/services/database/pois/fetchPoiDataByIdService.js";
|
||||||
import AddPOIModal from "@/components/pois/AddPOIModal.js";
|
import AddPOIModal from "@/components/pois/AddPOIModal.js";
|
||||||
@@ -39,6 +48,8 @@ import { setSelectedPoi } from "@/redux/slices/database/pois/selectedPoiSlice.js
|
|||||||
import { setDisabled } from "@/redux/slices/database/polylines/polylineEventsDisabledSlice.js";
|
import { setDisabled } from "@/redux/slices/database/polylines/polylineEventsDisabledSlice.js";
|
||||||
import { setMapId, setUserId } from "@/redux/slices/urlParameterSlice";
|
import { setMapId, setUserId } from "@/redux/slices/urlParameterSlice";
|
||||||
import { selectMapLayersState, setLayerVisibility } from "@/redux/slices/mapLayersSlice";
|
import { selectMapLayersState, setLayerVisibility } from "@/redux/slices/mapLayersSlice";
|
||||||
|
import { setSelectedArea } from "@/redux/slices/selectedAreaSlice";
|
||||||
|
import { incrementZoomTrigger } from "@/redux/slices/zoomTriggerSlice";
|
||||||
import { setCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice.js";
|
import { setCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice.js";
|
||||||
import { selectGisLines } from "@/redux/slices/database/polylines/gisLinesSlice";
|
import { selectGisLines } from "@/redux/slices/database/polylines/gisLinesSlice";
|
||||||
import { selectGisLinesStatus } from "@/redux/slices/webservice/gisLinesStatusSlice";
|
import { selectGisLinesStatus } from "@/redux/slices/webservice/gisLinesStatusSlice";
|
||||||
@@ -129,6 +140,13 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
const { data: gisLinesStatusData, status: statusGisLinesStatus } = useSelector(
|
const { data: gisLinesStatusData, status: statusGisLinesStatus } = useSelector(
|
||||||
selectGisLinesStatusFromWebservice
|
selectGisLinesStatusFromWebservice
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Alarm Status aus GisStationsStatusDistrict
|
||||||
|
const gisStationsStatusDistrict = useSelector(state => state.gisStationsStatusDistrict.data);
|
||||||
|
// Unterstützt sowohl Array-Shape (Statis[]) als auch Objekt mit Statis-Array
|
||||||
|
const hasActiveAlarm = Array.isArray(gisStationsStatusDistrict)
|
||||||
|
? gisStationsStatusDistrict.some(item => item?.Alarm === 1)
|
||||||
|
: gisStationsStatusDistrict?.Statis?.some(item => item?.Alarm === 1) || false;
|
||||||
const poiIconsData = useSelector(selectPoiIconsData);
|
const poiIconsData = useSelector(selectPoiIconsData);
|
||||||
const poiIconsStatus = useSelector(selectPoiIconsStatus);
|
const poiIconsStatus = useSelector(selectPoiIconsStatus);
|
||||||
const poiTypData = useSelector(selectPoiTypData);
|
const poiTypData = useSelector(selectPoiTypData);
|
||||||
@@ -147,10 +165,39 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
|
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
|
||||||
const [poiTypMap, setPoiTypMap] = useState(new Map());
|
const [poiTypMap, setPoiTypMap] = useState(new Map());
|
||||||
const [showPopup, setShowPopup] = useState(false);
|
const [showPopup, setShowPopup] = useState(false);
|
||||||
|
const [showAreaDropdown, setShowAreaDropdown] = useState(false);
|
||||||
const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker
|
const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker
|
||||||
const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte
|
const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte
|
||||||
const [map, setMap] = useState(null); // Zustand der Karteninstanz
|
const [map, setMap] = useState(null); // Zustand der Karteninstanz
|
||||||
const [oms, setOms] = useState(null); // State für OMS-Instanz
|
const [oms, setOms] = useState(null); // State für OMS-Instanz
|
||||||
|
// Sichtbarkeit der App-Info-Karte (unten links)
|
||||||
|
const [showAppInfoCard, setShowAppInfoCard] = useState(() => {
|
||||||
|
try {
|
||||||
|
const v = localStorage.getItem("showAppInfoCard");
|
||||||
|
return v === null ? true : v === "true";
|
||||||
|
} catch (_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Sichtbarkeit des Layer-Kontrollpanels (oben rechts)
|
||||||
|
const [showLayersPanel, setShowLayersPanel] = useState(() => {
|
||||||
|
try {
|
||||||
|
const v = localStorage.getItem("showLayersPanel");
|
||||||
|
return v === null ? true : v === "true";
|
||||||
|
} catch (_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Base-Map Panel wurde entfernt
|
||||||
|
// Sichtbarkeit der Koordinaten-Suche (Lupe)
|
||||||
|
const [showCoordinateInput, setShowCoordinateInput] = useState(() => {
|
||||||
|
try {
|
||||||
|
const v = localStorage.getItem("showCoordinateInput");
|
||||||
|
return v === null ? false : v === "true";
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Flag, ob Nutzer die Polyline-Checkbox manuell betätigt hat
|
// Flag, ob Nutzer die Polyline-Checkbox manuell betätigt hat
|
||||||
// Nutzer-Flag global auf window, damit auch Redux darauf zugreifen kann
|
// Nutzer-Flag global auf window, damit auch Redux darauf zugreifen kann
|
||||||
@@ -188,6 +235,14 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
const [popupCoordinates, setPopupCoordinates] = useState(null);
|
const [popupCoordinates, setPopupCoordinates] = useState(null);
|
||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [poiData, setPoiData] = useState([]);
|
const [poiData, setPoiData] = useState([]);
|
||||||
|
// Edit mode state mirrors MapLayersControlPanel's behavior
|
||||||
|
const [editMode, setEditMode] = useState(() => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem("editMode") === "true";
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const openVersionInfoModal = () => {
|
const openVersionInfoModal = () => {
|
||||||
setShowVersionInfoModal(true);
|
setShowVersionInfoModal(true);
|
||||||
@@ -209,6 +264,26 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Persistiere Sichtbarkeit der App-Info-Karte
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem("showAppInfoCard", String(showAppInfoCard));
|
||||||
|
} catch (_) {}
|
||||||
|
}, [showAppInfoCard]);
|
||||||
|
// Persistiere Sichtbarkeit des Layer-Panels
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem("showLayersPanel", String(showLayersPanel));
|
||||||
|
} catch (_) {}
|
||||||
|
}, [showLayersPanel]);
|
||||||
|
// Persist-Logik für Base-Map Panel entfernt
|
||||||
|
// Persistiere Sichtbarkeit der Koordinaten-Suche
|
||||||
|
useEffect(() => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem("showCoordinateInput", String(showCoordinateInput));
|
||||||
|
} catch (_) {}
|
||||||
|
}, [showCoordinateInput]);
|
||||||
|
|
||||||
//--------------------------------------------
|
//--------------------------------------------
|
||||||
|
|
||||||
const handleCoordinatesSubmit = coords => {
|
const handleCoordinatesSubmit = coords => {
|
||||||
@@ -981,6 +1056,29 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
}, [GisSystemStatic, mapLayersVisibility, dispatch]);
|
}, [GisSystemStatic, mapLayersVisibility, dispatch]);
|
||||||
|
|
||||||
//---------------------------------------------
|
//---------------------------------------------
|
||||||
|
//--------------------------------------------
|
||||||
|
// Expand handler (same behavior as MapLayersControlPanel expand icon)
|
||||||
|
const handleExpandClick = () => {
|
||||||
|
dispatch(setSelectedArea("Station wählen"));
|
||||||
|
dispatch(incrementZoomTrigger());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle edit mode (same logic as EditModeToggle component)
|
||||||
|
const hasEditRight = Array.isArray(userRights)
|
||||||
|
? userRights.includes?.(56) || userRights.some?.(r => r?.IdRight === 56)
|
||||||
|
: false;
|
||||||
|
const toggleEditMode = () => {
|
||||||
|
if (!hasEditRight) return;
|
||||||
|
const next = !editMode;
|
||||||
|
setEditMode(next);
|
||||||
|
try {
|
||||||
|
localStorage.setItem("editMode", String(next));
|
||||||
|
} catch (_) {}
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//--------------------------------------------
|
//--------------------------------------------
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -1035,31 +1133,135 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{GisStationsStaticDistrict && GisStationsStaticDistrict.Points?.length > 0 && (
|
{GisStationsStaticDistrict &&
|
||||||
<MapLayersControlPanel
|
GisStationsStaticDistrict.Points?.length > 0 &&
|
||||||
className="z-50"
|
showLayersPanel &&
|
||||||
handlePolylineCheckboxChange={handlePolylineCheckboxChange}
|
!showAreaDropdown && (
|
||||||
/>
|
<MapLayersControlPanel
|
||||||
)}
|
className="z-50"
|
||||||
|
handlePolylineCheckboxChange={handlePolylineCheckboxChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<CoordinateInput onCoordinatesSubmit={handleCoordinatesSubmit} />
|
{showCoordinateInput && <CoordinateInput onCoordinatesSubmit={handleCoordinatesSubmit} />}
|
||||||
<div id="map" ref={mapRef} className="z-0" style={{ height: "100vh", width: "100vw" }}></div>
|
<div id="map" ref={mapRef} className="z-0" style={{ height: "100vh", width: "100vw" }}></div>
|
||||||
|
{/* Top-right controls: layers, info, expand, edit, and base map stack */}
|
||||||
|
<div className="absolute top-3 right-3 z-50 pointer-events-auto flex items-center gap-2">
|
||||||
|
{/* Alarm-Icon - nur anzeigen wenn Alarm aktiv */}
|
||||||
|
{hasActiveAlarm && (
|
||||||
|
<button
|
||||||
|
onClick={() => {}}
|
||||||
|
aria-label="Alarm aktiv"
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||||
|
title="Alarm aktiv"
|
||||||
|
>
|
||||||
|
<AlarmIcon className="h-8 w-8 animate-pulse text-red-500" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{/* Marker-Icon (line-md) */}
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setShowAreaDropdown(v => {
|
||||||
|
const next = !v;
|
||||||
|
if (next) setShowLayersPanel(false); // Dropdown öffnen -> Panel schließen
|
||||||
|
return next;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
aria-label="Marker"
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||||
|
title="Marker"
|
||||||
|
>
|
||||||
|
<MapMarkerIcon className="h-8 w-8" />
|
||||||
|
</button>
|
||||||
|
{showAreaDropdown && <AreaDropdown onClose={() => setShowAreaDropdown(false)} />}
|
||||||
|
{/*Lupe: Koordinatensuche ein-/ausblenden */}
|
||||||
|
<button
|
||||||
|
onClick={() => setShowCoordinateInput(v => !v)}
|
||||||
|
aria-label={
|
||||||
|
showCoordinateInput ? "Koordinatensuche ausblenden" : "Koordinatensuche einblenden"
|
||||||
|
}
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||||
|
title={
|
||||||
|
showCoordinateInput ? "Koordinatensuche ausblenden" : "Koordinatensuche einblenden"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SearchIcon className="h-8 w-8" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={toggleEditMode}
|
||||||
|
aria-label={editMode ? "Bearbeitungsmodus deaktivieren" : "Bearbeitungsmodus aktivieren"}
|
||||||
|
className={`rounded-full shadow p-1 ${
|
||||||
|
hasEditRight
|
||||||
|
? "bg-white/90 hover:bg-white"
|
||||||
|
: "bg-white/60 cursor-not-allowed opacity-50"
|
||||||
|
}`}
|
||||||
|
title={
|
||||||
|
hasEditRight
|
||||||
|
? editMode
|
||||||
|
? "Bearbeitungsmodus deaktivieren"
|
||||||
|
: "Bearbeitungsmodus aktivieren"
|
||||||
|
: "Keine Bearbeitungsrechte"
|
||||||
|
}
|
||||||
|
disabled={!hasEditRight}
|
||||||
|
>
|
||||||
|
{editMode ? <EditOffIcon className="h-8 w-8" /> : <EditIcon className="h-8 w-8" />}
|
||||||
|
</button>
|
||||||
|
{/* Expand: Karte auf Standardansicht */}
|
||||||
|
<button
|
||||||
|
onClick={handleExpandClick}
|
||||||
|
aria-label="Karte auf Standardansicht"
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1 "
|
||||||
|
title="Karte auf Standardansicht"
|
||||||
|
>
|
||||||
|
<ExpandIcon className="h-8 w-8" />
|
||||||
|
</button>
|
||||||
|
{/* Lupe: Koordinaten-Suche ein-/ausblenden */}
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
setShowLayersPanel(v => {
|
||||||
|
const next = !v;
|
||||||
|
if (next) setShowAreaDropdown(false); // Panel öffnen -> Dropdown schließen
|
||||||
|
return next;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
aria-label={showLayersPanel ? "Layer-Panel ausblenden" : "Layer-Panel einblenden"}
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||||
|
title={showLayersPanel ? "Layer-Panel ausblenden" : "Layer-Panel einblenden"}
|
||||||
|
>
|
||||||
|
<MenuIcon className="h-8 w-8" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setShowAppInfoCard(v => !v)}
|
||||||
|
aria-label={showAppInfoCard ? "Info ausblenden" : "Info einblenden"}
|
||||||
|
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||||
|
title={showAppInfoCard ? "Info ausblenden" : "Info einblenden"}
|
||||||
|
>
|
||||||
|
<InfoIcon
|
||||||
|
className="h-8 w-8 pr-1"
|
||||||
|
title={showAppInfoCard ? "Info ausblenden" : "Info einblenden"}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/* BaseMapPanel entfernt */}
|
||||||
<CoordinatePopup isOpen={isPopupOpen} coordinates={currentCoordinates} onClose={closePopup} />
|
<CoordinatePopup isOpen={isPopupOpen} coordinates={currentCoordinates} onClose={closePopup} />
|
||||||
|
|
||||||
<div className="absolute bottom-3 left-3 w-72 p-4 bg-white rounded-lg shadow-md z-50">
|
{showAppInfoCard && (
|
||||||
<div className="flex justify-between items-center">
|
<div className="absolute bottom-3 left-3 w-72 p-4 bg-white rounded-lg shadow-md z-50">
|
||||||
<div>
|
<div className="flex justify-between items-center">
|
||||||
<span className="text-black text-lg font-semibold"> TALAS.Map </span>
|
<div>
|
||||||
<br />
|
<span className="text-black text-lg font-semibold"> TALAS.Map </span>
|
||||||
<span className="text-black text-lg">Version {appVersion}</span>
|
<br />
|
||||||
</div>
|
<span className="text-black text-lg">Version {appVersion}</span>
|
||||||
<div>
|
</div>
|
||||||
<button onClick={openVersionInfoModal}>
|
<div>
|
||||||
<InformationCircleIcon className="text-blue-900 h-8 w-8 pr-1" title="Weitere Infos" />
|
<button onClick={openVersionInfoModal}>
|
||||||
</button>
|
<InfoIcon className="h-8 w-8 pr-1" title="Weitere Infos" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
<VersionInfoModal
|
<VersionInfoModal
|
||||||
showVersionInfoModal={showVersionInfoModal}
|
showVersionInfoModal={showVersionInfoModal}
|
||||||
closeVersionInfoModal={closeVersionInfoModal}
|
closeVersionInfoModal={closeVersionInfoModal}
|
||||||
|
|||||||
79
components/uiWidgets/AreaDropdown.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// /components/uiWidgets/AreaDropdown.js
|
||||||
|
import React, { useEffect, useMemo } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { setSelectedArea } from "@/redux/slices/selectedAreaSlice";
|
||||||
|
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
|
||||||
|
import { selectGisSystemStatic } from "@/redux/slices/webservice/gisSystemStaticSlice";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kleines Dropdown zur Auswahl der Station (Area_Name),
|
||||||
|
* nutzt dieselbe Datenquelle wie das MapLayersControlPanel.
|
||||||
|
*/
|
||||||
|
const AreaDropdown = ({ onClose }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict) || {};
|
||||||
|
const GisSystemStatic = useSelector(selectGisSystemStatic) || [];
|
||||||
|
|
||||||
|
// Erlaubte Systeme: Allow === 1 und Map === 1
|
||||||
|
const allowedSystems = useMemo(() => {
|
||||||
|
return new Set(
|
||||||
|
(Array.isArray(GisSystemStatic) ? GisSystemStatic : [])
|
||||||
|
.filter(sys => sys.Allow === 1 && sys.Map === 1)
|
||||||
|
.map(sys => sys.IdSystem)
|
||||||
|
);
|
||||||
|
}, [GisSystemStatic]);
|
||||||
|
|
||||||
|
// Uniqe Areas basierend auf Allowed Systems
|
||||||
|
const areaOptions = useMemo(() => {
|
||||||
|
const points = GisStationsStaticDistrict?.Points || [];
|
||||||
|
const seen = new Set();
|
||||||
|
const filtered = points.filter(p => {
|
||||||
|
if (!p?.Area_Name) return false;
|
||||||
|
if (!allowedSystems.has(p.System)) return false;
|
||||||
|
if (seen.has(p.Area_Name)) return false;
|
||||||
|
seen.add(p.Area_Name);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return filtered.map(p => ({ label: p.Area_Name, value: p.IdLD }));
|
||||||
|
}, [GisStationsStaticDistrict, allowedSystems]);
|
||||||
|
|
||||||
|
const handleChange = e => {
|
||||||
|
const selectedIndex = e.target.options.selectedIndex;
|
||||||
|
const label = e.target.options[selectedIndex].text;
|
||||||
|
dispatch(setSelectedArea(label));
|
||||||
|
onClose?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Schließe mit ESC
|
||||||
|
useEffect(() => {
|
||||||
|
const onKey = e => {
|
||||||
|
if (e.key === "Escape") onClose?.();
|
||||||
|
};
|
||||||
|
window.addEventListener("keydown", onKey);
|
||||||
|
return () => window.removeEventListener("keydown", onKey);
|
||||||
|
}, [onClose]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute top-16 right-3 z-[60]">
|
||||||
|
<div className="bg-white rounded-md shadow-lg p-3 border border-gray-200 min-w-[220px]">
|
||||||
|
<div className="text-sm font-semibold mb-2">Station wählen</div>
|
||||||
|
<select
|
||||||
|
onChange={handleChange}
|
||||||
|
className="border p-2 rounded w-full"
|
||||||
|
defaultValue="__default__"
|
||||||
|
>
|
||||||
|
<option value="__default__" disabled>
|
||||||
|
Bitte wählen…
|
||||||
|
</option>
|
||||||
|
{areaOptions.map(opt => (
|
||||||
|
<option key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AreaDropdown;
|
||||||
@@ -4,7 +4,7 @@ import React, { useState } from "react";
|
|||||||
const CoordinateInput = ({ onCoordinatesSubmit }) => {
|
const CoordinateInput = ({ onCoordinatesSubmit }) => {
|
||||||
const [coordinates, setCoordinates] = useState("");
|
const [coordinates, setCoordinates] = useState("");
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
const handleSubmit = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (onCoordinatesSubmit) {
|
if (onCoordinatesSubmit) {
|
||||||
onCoordinatesSubmit(coordinates);
|
onCoordinatesSubmit(coordinates);
|
||||||
@@ -12,9 +12,21 @@ const CoordinateInput = ({ onCoordinatesSubmit }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className="fixed top-5 left-5 z-50 bg-white shadow-lg rounded-lg p-4 w-72">
|
<form
|
||||||
<input type="text" placeholder="Koordinaten eingeben (lat,lng)" value={coordinates} onChange={(e) => setCoordinates(e.target.value)} className="border p-2 rounded w-full mb-2" />
|
onSubmit={handleSubmit}
|
||||||
<button type="submit" className="bg-blue-500 text-white p-2 rounded w-full hover:bg-blue-600">
|
className="fixed top-5 left-5 z-50 bg-white shadow-lg rounded-lg p-4 w-72"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Koordinaten eingeben (lat,lng)"
|
||||||
|
value={coordinates}
|
||||||
|
onChange={e => setCoordinates(e.target.value)}
|
||||||
|
className="border p-2 rounded w-full mb-2"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="bg-littwin-blue text-white p-2 rounded w-full hover:bg-blue-600"
|
||||||
|
>
|
||||||
Zu Marker zoomen
|
Zu Marker zoomen
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const VersionInfoModal = ({ showVersionInfoModal, closeVersionInfoModal, APP_VER
|
|||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={closeVersionInfoModal}
|
onClick={closeVersionInfoModal}
|
||||||
className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-700 mx-auto block"
|
className="mt-4 bg-littwin-blue text-white px-4 py-2 rounded mx-auto block"
|
||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
163
components/uiWidgets/baseMapPanel/BaseMapPanel.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
// components/uiWidgets/baseMapPanel/BaseMapPanel.js
|
||||||
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import L from "leaflet";
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
|
||||||
|
// Minimal, safe defaults (no API key required). You can extend via config later.
|
||||||
|
const DEFAULT_BASE_LAYERS = [
|
||||||
|
{
|
||||||
|
id: "osm-standard",
|
||||||
|
name: "Standard",
|
||||||
|
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
|
attribution: "© OpenStreetMap contributors",
|
||||||
|
minZoom: 0,
|
||||||
|
maxZoom: 19,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "osm-humanitarian",
|
||||||
|
name: "Humanitarian",
|
||||||
|
url: "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
||||||
|
attribution: "© OpenStreetMap contributors, Humanitarian OpenStreetMap Team",
|
||||||
|
minZoom: 0,
|
||||||
|
maxZoom: 19,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "cyclosm",
|
||||||
|
name: "CyclOSM",
|
||||||
|
url: "https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png",
|
||||||
|
attribution: "© OpenStreetMap contributors, CyclOSM",
|
||||||
|
minZoom: 0,
|
||||||
|
maxZoom: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "carto-light",
|
||||||
|
name: "Carto Light",
|
||||||
|
url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
||||||
|
attribution: "© OpenStreetMap contributors, © CARTO",
|
||||||
|
subdomains: "abcd",
|
||||||
|
minZoom: 0,
|
||||||
|
maxZoom: 20,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function getCurrentTileLayer(map) {
|
||||||
|
let found = null;
|
||||||
|
if (!map) return null;
|
||||||
|
map.eachLayer(layer => {
|
||||||
|
if (!found && layer instanceof L.TileLayer) {
|
||||||
|
found = layer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BaseMapPanel({ map, onSelect, onClose, initialId }) {
|
||||||
|
const [activeId, setActiveId] = useState(initialId || null);
|
||||||
|
const layerCacheRef = useRef({});
|
||||||
|
const bases = useMemo(() => {
|
||||||
|
try {
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
const cfg = window.__leafletConfig;
|
||||||
|
if (cfg && cfg.tileSources) {
|
||||||
|
return Object.entries(cfg.tileSources).map(([key, ts]) => ({
|
||||||
|
id: key,
|
||||||
|
name: ts.name || key,
|
||||||
|
url: ts.url,
|
||||||
|
attribution: ts.attribution || "© OpenStreetMap contributors",
|
||||||
|
minZoom: ts.minZoom ?? cfg.minZoom ?? 0,
|
||||||
|
maxZoom: ts.maxZoom ?? cfg.maxZoom ?? 19,
|
||||||
|
subdomains: ts.subdomains,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
return DEFAULT_BASE_LAYERS;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const applyBase = id => {
|
||||||
|
if (!map) return;
|
||||||
|
const base = bases.find(b => b.id === id) || bases[0];
|
||||||
|
if (!base) return;
|
||||||
|
|
||||||
|
// Remove current tile layer
|
||||||
|
const current = getCurrentTileLayer(map);
|
||||||
|
if (current) {
|
||||||
|
try {
|
||||||
|
map.removeLayer(current);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get or create the new layer
|
||||||
|
let nextLayer = layerCacheRef.current[id];
|
||||||
|
if (!nextLayer) {
|
||||||
|
nextLayer = L.tileLayer(base.url, {
|
||||||
|
attribution: base.attribution,
|
||||||
|
subdomains: base.subdomains || "abc",
|
||||||
|
tileSize: 256,
|
||||||
|
minZoom: base.minZoom ?? 0,
|
||||||
|
maxZoom: base.maxZoom ?? 19,
|
||||||
|
noWrap: true,
|
||||||
|
// Ensure base tiles stay behind overlays
|
||||||
|
zIndex: 1,
|
||||||
|
});
|
||||||
|
layerCacheRef.current[id] = nextLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextLayer.addTo(map);
|
||||||
|
try {
|
||||||
|
if (typeof map.setMinZoom === "function") map.setMinZoom(base.minZoom ?? 0);
|
||||||
|
if (typeof map.setMaxZoom === "function") map.setMaxZoom(base.maxZoom ?? 19);
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.__tileSourceMinZoom = base.minZoom ?? 0;
|
||||||
|
window.__tileSourceMaxZoom = base.maxZoom ?? 19;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
setActiveId(id);
|
||||||
|
try {
|
||||||
|
localStorage.setItem("baseMapId", id);
|
||||||
|
} catch (_) {}
|
||||||
|
onSelect && onSelect(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const saved = (() => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem("baseMapId");
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
const targetId = initialId || saved || bases[0]?.id;
|
||||||
|
if (targetId) {
|
||||||
|
applyBase(targetId);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [map]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute top-16 right-3 z-50 w-64 bg-white rounded-lg shadow-lg p-3">
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<h3 className="text-sm font-semibold">Map Layers</h3>
|
||||||
|
<button onClick={onClose} aria-label="Schließen" title="Schließen">
|
||||||
|
<Icon icon="material-symbols:close-rounded" className="h-5 w-5 text-gray-700" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
{bases.map(b => (
|
||||||
|
<button
|
||||||
|
key={b.id}
|
||||||
|
onClick={() => applyBase(b.id)}
|
||||||
|
className={`text-left rounded-md border p-2 hover:bg-gray-50 ${
|
||||||
|
activeId === b.id ? "ring-2 ring-blue-500" : ""
|
||||||
|
}`}
|
||||||
|
title={b.name}
|
||||||
|
>
|
||||||
|
<div className="font-medium text-sm">{b.name}</div>
|
||||||
|
<div className="text-[10px] text-gray-500 truncate">{b.url}</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -241,28 +241,55 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
|
|||||||
}, [GisStationsStaticDistrict]);
|
}, [GisStationsStaticDistrict]);
|
||||||
//---------------------------
|
//---------------------------
|
||||||
|
|
||||||
|
// Polyline (Kabelstrecken) abhängig von TALAS (system-1)
|
||||||
|
const onPolylineToggle = checked => {
|
||||||
|
if (editMode) return;
|
||||||
|
|
||||||
|
// Wenn Nutzer Kabelstrecken einschaltet, aber TALAS aktuell ausgeblendet ist,
|
||||||
|
// dann TALAS automatisch aktivieren (sofern erlaubt)
|
||||||
|
const talasKey = "system-1";
|
||||||
|
const talasVisible = !!mapLayersVisibility[talasKey];
|
||||||
|
if (checked && isTalasAllowed && !talasVisible) {
|
||||||
|
dispatch(setLayerVisibility({ layer: talasKey, visibility: true }));
|
||||||
|
|
||||||
|
// Persistiere Sichtbarkeit map/user-spezifisch
|
||||||
|
const mapId2 = localStorage.getItem("currentMapId");
|
||||||
|
const userId2 = localStorage.getItem("currentUserId");
|
||||||
|
const mapStorageKey =
|
||||||
|
mapId2 && userId2 ? `mapLayersVisibility_m${mapId2}_u${userId2}` : "mapLayersVisibility";
|
||||||
|
localStorage.setItem(
|
||||||
|
mapStorageKey,
|
||||||
|
JSON.stringify({ ...mapLayersVisibility, [talasKey]: true })
|
||||||
|
);
|
||||||
|
|
||||||
|
// Event feuern wie an anderer Stelle
|
||||||
|
setTimeout(() => {
|
||||||
|
const event = new Event("visibilityChanged");
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sichtbarkeit der Kabelstrecken setzen
|
||||||
|
handlePolylineCheckboxChange(checked);
|
||||||
|
};
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="mainDataSheet"
|
id="mainDataSheet"
|
||||||
className="absolute top-3 right-3 w-1/6 min-w-[300px] max-w-[400px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
className="absolute top-16 right-3 w-1/6 min-w-[300px] max-w-[200px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-4 p-4">
|
<div className="flex flex-col gap-4 p-4">
|
||||||
<div className="flex items-center justify-between space-x-2">
|
<div className="flex items-center justify-between space-x-2">
|
||||||
<select
|
{/*
|
||||||
|
<select
|
||||||
onChange={handleAreaChange}
|
onChange={handleAreaChange}
|
||||||
id="stationListing"
|
id="stationListing"
|
||||||
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
||||||
style={{ minWidth: "150px", maxWidth: "200px" }}
|
style={{ minWidth: "150px", maxWidth: "200px" }}
|
||||||
>
|
>
|
||||||
<option value="Station wählen">Station wählen</option>
|
<option value="Station wählen">Station wählen</option>
|
||||||
{/*
|
|
||||||
...new Map(
|
|
||||||
(GisStationsStaticDistrict.Points || [])
|
|
||||||
.filter(p => !!p.Area_Name)
|
|
||||||
.map(p => [p.Area_Name, p])
|
|
||||||
).values(),
|
|
||||||
*/}
|
|
||||||
{[
|
{[
|
||||||
...new Map(
|
...new Map(
|
||||||
(GisStationsStaticDistrict.Points || [])
|
(GisStationsStaticDistrict.Points || [])
|
||||||
@@ -275,6 +302,9 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
*/}
|
||||||
|
|
||||||
|
{/*
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<EditModeToggle />
|
<EditModeToggle />
|
||||||
<img
|
<img
|
||||||
@@ -284,6 +314,7 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
|
|||||||
onClick={handleIconClick}
|
onClick={handleIconClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
*/}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Checkboxen mit Untermenüs */}
|
{/* Checkboxen mit Untermenüs */}
|
||||||
@@ -310,7 +341,7 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
|
|||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={kabelstreckenVisible}
|
checked={kabelstreckenVisible}
|
||||||
onChange={e => handlePolylineCheckboxChange(e.target.checked)}
|
onChange={e => onPolylineToggle(e.target.checked)}
|
||||||
id="polyline-checkbox"
|
id="polyline-checkbox"
|
||||||
disabled={!isTalasAllowed || editMode}
|
disabled={!isTalasAllowed || editMode}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -102,3 +102,4 @@ Station suchen
|
|||||||
Hamburger-Menü
|
Hamburger-Menü
|
||||||
- [ ] TODO: Info Karte: VersionInfoModal.js Modal soll über einem Icon 'Info' oben rechts
|
- [ ] TODO: Info Karte: VersionInfoModal.js Modal soll über einem Icon 'Info' oben rechts
|
||||||
eingeblendet und ausgeblendet um mehr von der Karte zu sehen ℹ️ Info
|
eingeblendet und ausgeblendet um mehr von der Karte zu sehen ℹ️ Info
|
||||||
|
https://www.openstreetmap.org/#map=13/51.80097/9.33495&layers=P
|
||||||
|
|||||||
@@ -22,4 +22,73 @@ Verzeichnisstruktur funktioniert.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## OSM‑basierte, „open“ Quellen
|
||||||
|
|
||||||
|
Diese sind datenrechtlich offen (ODbL bzw. Community-Lizenzen), aber das „kostenlos“ gilt nicht im
|
||||||
|
Sinne unbegrenzter Tile‑Nutzung. Die Tile‑Server werden als Community‑Ressource bereitgestellt –
|
||||||
|
bitte Policies respektieren.
|
||||||
|
|
||||||
|
- osm-standard (OpenStreetMap)
|
||||||
|
- - Key: Nein
|
||||||
|
- - Nutzung: Fair‑Use; für produktive/hohe Last eigenen Tile‑Server/Provider verwenden.
|
||||||
|
- - Attribution: „© OpenStreetMap contributors“
|
||||||
|
|
||||||
|
- osm-humanitarian (HOT)
|
||||||
|
- - Key: Nein
|
||||||
|
- - Nutzung: Fair‑Use; für größere Last die Betreiber kontaktieren bzw. andere Infrastruktur nutzen.
|
||||||
|
- - Attribution: „© OpenStreetMap contributors <br>
|
||||||
|
-
|
||||||
|
- Humanitarian OpenStreetMap Team“ cyclosm
|
||||||
|
- - Key: Nein
|
||||||
|
- - Nutzung: Fair‑Use (bereitgestellt u. a. über OSM France). Für höhere Last
|
||||||
|
Unterstützung/Hostingoptionen prüfen.
|
||||||
|
- - Attribution: „CyclOSM“ + „OpenStreetMap contributors“
|
||||||
|
- Praxis‑Tipps Kleine bis mittlere Nutzung: Die oben genannten „keyless“ Quellen sind oft
|
||||||
|
ausreichend, solange du Attribution setzt und Limits respektierst. Produktion/hohe Last: Nutze
|
||||||
|
einen Anbieter mit Vertrag/Key (z. B. Thunderforest, Tracestrack, MapTiler, Mapbox) oder hoste
|
||||||
|
Tiles selbst. Schlüssel im Client: Für Thunderforest/Tracestrack stehen die Keys im Frontend. Das
|
||||||
|
ist üblich, aber der Key ist sichtbar. Wenn du ihn verbergen willst, richte einen kleinen
|
||||||
|
Tile‑Proxy auf deinem Server ein, der den Key serverseitig anhängt und optional cached.
|
||||||
|
Attribution: Dein BaseMapPanel setzt bereits Attributionsstrings aus config.json. Achte darauf,
|
||||||
|
dass sie je Quelle korrekt sind.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Kurzantwort: Für kommerzielle Nutzung sind OSM‑Community‑Tile‑Server nicht geeignet. Nutze einen
|
||||||
|
bezahlten Anbieter (z. B. Thunderforest, Tracestrack) oder hoste selbst. Attribution ist immer
|
||||||
|
Pflicht.
|
||||||
|
|
||||||
|
Links und Hinweise je Layer/Provider:
|
||||||
|
|
||||||
|
OpenStreetMap Standard (osm-standard)
|
||||||
|
|
||||||
|
Lizenz/Daten: ODbL, Attribution Pflicht Tile-Server-Policy (keine Produktion/hohe Last):
|
||||||
|
https://operations.osmfoundation.org/policies/tiles/ Urheberrecht/Attribution:
|
||||||
|
https://www.openstreetmap.org/copyright HOT Humanitarian (osm-humanitarian)
|
||||||
|
|
||||||
|
Community-Server (OSM France); keine Produktion/hohe Last Info/Policy OSM France Tiles:
|
||||||
|
https://tile.openstreetmap.fr/ HOT: https://www.hotosm.org/ CyclOSM (cyclosm)
|
||||||
|
|
||||||
|
Community-Server (OSM France); keine Produktion/hohe Last Projektseite: https://www.cyclosm.org/
|
||||||
|
Hinweise/Policy (OSM France): https://tile.openstreetmap.fr/ Wiki:
|
||||||
|
https://wiki.openstreetmap.org/wiki/CyclOSM Carto Light (carto-light / Positron)
|
||||||
|
|
||||||
|
Keylos nutzbar mit Attribution; Fair‑Use, für hohe Last über CARTO‑Pläne Basemaps:
|
||||||
|
https://carto.com/basemaps/ Attribution: https://carto.com/attributions Pricing (Plattform):
|
||||||
|
https://carto.com/pricing/ (bei großem Volumen Sales kontaktieren) Thunderforest (Cycle/Transport u.
|
||||||
|
a.)
|
||||||
|
|
||||||
|
Kommerziell mit API‑Key; Pläne von Free bis Pro Pricing: https://www.thunderforest.com/pricing/
|
||||||
|
Terms/Attribution: https://www.thunderforest.com/terms/ Tracestrack Topo
|
||||||
|
|
||||||
|
API‑Key erforderlich; kostenlose und bezahlte Pläne Übersicht/Pricing:
|
||||||
|
https://www.tracestrack.com/en/maps/ Nutzungsbedingungen: https://www.tracestrack.com/en/terms/
|
||||||
|
Empfehlung:
|
||||||
|
|
||||||
|
Produktion: Nimm Thunderforest oder Tracestrack (oder MapTiler: https://www.maptiler.com/pricing/)
|
||||||
|
oder hoste Tiles selbst. Attribution in der Karte anzeigen (OSM + jeweiliger Anbieter). Soll ich
|
||||||
|
diese Links samt klarer Hinweise kompakt in eure README.md einpflegen?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
[Zurück zur Übersicht](../README.md)
|
[Zurück zur Übersicht](../README.md)
|
||||||
|
|||||||
26
package-lock.json
generated
@@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "nodemap",
|
"name": "nodemap",
|
||||||
"version": "1.1.355",
|
"version": "1.1.369",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "nodemap",
|
"name": "nodemap",
|
||||||
"version": "1.1.355",
|
"version": "1.1.369",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.3",
|
"@emotion/react": "^11.13.3",
|
||||||
"@emotion/styled": "^11.13.0",
|
"@emotion/styled": "^11.13.0",
|
||||||
"@heroicons/react": "^2.1.5",
|
"@heroicons/react": "^2.1.5",
|
||||||
|
"@iconify/react": "^6.0.1",
|
||||||
"@mui/icons-material": "^6.0.2",
|
"@mui/icons-material": "^6.0.2",
|
||||||
"@reduxjs/toolkit": "^2.5.1",
|
"@reduxjs/toolkit": "^2.5.1",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
@@ -357,6 +358,27 @@
|
|||||||
"react": ">= 16 || ^19.0.0-rc"
|
"react": ">= 16 || ^19.0.0-rc"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@iconify/react": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify/react/-/react-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-fCocnAfiGXjrA0u7KkS3W/OQHNp9LRFICudvOtxmS3Mf7U92aDhP50wyzRbobZli51zYt9ksZ9g0J7H586XvOQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@iconify/types": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/cyberalien"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@iconify/types": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "nodemap",
|
"name": "nodemap",
|
||||||
"version": "1.1.355",
|
"version": "1.1.369",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.13.3",
|
"@emotion/react": "^11.13.3",
|
||||||
"@emotion/styled": "^11.13.0",
|
"@emotion/styled": "^11.13.0",
|
||||||
"@heroicons/react": "^2.1.5",
|
"@heroicons/react": "^2.1.5",
|
||||||
|
"@iconify/react": "^6.0.1",
|
||||||
"@mui/icons-material": "^6.0.2",
|
"@mui/icons-material": "^6.0.2",
|
||||||
"@reduxjs/toolkit": "^2.5.1",
|
"@reduxjs/toolkit": "^2.5.1",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
|
|||||||
@@ -17,6 +17,61 @@
|
|||||||
"_comment": "OpenStreetMap Online-Kartenquelle über Server-Proxy (relativ)",
|
"_comment": "OpenStreetMap Online-Kartenquelle über Server-Proxy (relativ)",
|
||||||
"minZoom": 0,
|
"minZoom": 0,
|
||||||
"maxZoom": 19
|
"maxZoom": 19
|
||||||
|
},
|
||||||
|
"osm-standard": {
|
||||||
|
"name": "Standard",
|
||||||
|
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
|
"attribution": "© OpenStreetMap contributors",
|
||||||
|
"subdomains": "abc",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 19
|
||||||
|
},
|
||||||
|
"osm-humanitarian": {
|
||||||
|
"name": "Humanitarian",
|
||||||
|
"url": "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
||||||
|
"attribution": "© OpenStreetMap contributors, Humanitarian OpenStreetMap Team",
|
||||||
|
"subdomains": "abc",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 19
|
||||||
|
},
|
||||||
|
"cyclosm": {
|
||||||
|
"name": "CyclOSM",
|
||||||
|
"url": "https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png",
|
||||||
|
"attribution": "© OpenStreetMap contributors, CyclOSM",
|
||||||
|
"subdomains": "abc",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 20
|
||||||
|
},
|
||||||
|
"carto-light": {
|
||||||
|
"name": "Carto Light",
|
||||||
|
"url": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
||||||
|
"attribution": "© OpenStreetMap contributors, © CARTO",
|
||||||
|
"subdomains": "abcd",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 20
|
||||||
|
},
|
||||||
|
"thunderforest-cycle": {
|
||||||
|
"name": "Cycle Map (Thunderforest)",
|
||||||
|
"url": "https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=YOUR_THUNDERFOREST_API_KEY",
|
||||||
|
"attribution": "© OpenStreetMap contributors, © Thunderforest",
|
||||||
|
"subdomains": "abc",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 22
|
||||||
|
},
|
||||||
|
"thunderforest-transport": {
|
||||||
|
"name": "Transport Map (Thunderforest)",
|
||||||
|
"url": "https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=YOUR_THUNDERFOREST_API_KEY",
|
||||||
|
"attribution": "© OpenStreetMap contributors, © Thunderforest",
|
||||||
|
"subdomains": "abc",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 22
|
||||||
|
},
|
||||||
|
"tracestrack-topo": {
|
||||||
|
"name": "Tracestrack Topo",
|
||||||
|
"url": "https://tile.tracestrack.com/topo__/{z}/{x}/{y}.webp?key=YOUR_TRACESTRACK_KEY",
|
||||||
|
"attribution": "© OpenStreetMap contributors, © Tracestrack",
|
||||||
|
"minZoom": 0,
|
||||||
|
"maxZoom": 19
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "osm",
|
"active": "osm",
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 349 B |
3
public/img/icons/material-symbols/alarm.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 396 B |
3
public/img/icons/material-symbols/edit-off.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L18 21l-3-3m-12.728-.364A9 9 0 015.636 5.636m0 0L3 3l3 3m9.364 9.364L18 21M5.636 5.636L3 3" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 351 B |
3
public/img/icons/material-symbols/edit.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 432 B |
3
public/img/icons/material-symbols/info.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 333 B |
4
public/img/icons/material-symbols/map-marker.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="rgb(0, 174, 239)" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25s-7.5-4.108-7.5-11.25a7.5 7.5 0 1115 0z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 373 B |
3
public/img/icons/material-symbols/menu.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 231 B |
3
public/img/icons/material-symbols/search.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="rgb(0, 174, 239)">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 261 B |
@@ -1,6 +1,10 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", "./hooks/**/*.{js,ts,jsx,tsx}"],
|
content: [
|
||||||
|
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./components/**/*.{js,ts,jsx,tsx}",
|
||||||
|
"./hooks/**/*.{js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
zIndex: {
|
zIndex: {
|
||||||
@@ -10,6 +14,9 @@ module.exports = {
|
|||||||
90: "90",
|
90: "90",
|
||||||
100: "100",
|
100: "100",
|
||||||
},
|
},
|
||||||
|
colors: {
|
||||||
|
"littwin-blue": "#00aeef",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 01 kommend",
|
"Me": "Eingang DE 01 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -15,7 +16,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 31 kommend",
|
"Me": "Eingang DE 31 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -24,7 +26,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 17 kommend",
|
"Me": "Eingang DE 17 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -33,7 +36,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 05 kommend",
|
"Me": "Eingang DE 05 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -42,7 +46,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 20 kommend",
|
"Me": "Eingang DE 20 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -51,7 +56,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 32 kommend",
|
"Me": "Eingang DE 32 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -60,7 +66,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 01 kommend",
|
"Me": "Eingang DE 01 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -69,7 +76,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Station offline",
|
"Me": "Station offline",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -78,7 +86,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 01 kommend",
|
"Me": "Eingang DE 01 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -87,7 +96,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Station offline",
|
"Me": "Station offline",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50066,
|
"IdLD": 50066,
|
||||||
@@ -96,7 +106,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "CPL offline",
|
"Me": "CPL offline",
|
||||||
"Feld": 5,
|
"Feld": 5,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50011,
|
"IdLD": 50011,
|
||||||
@@ -105,7 +116,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "CPL offline",
|
"Me": "CPL offline",
|
||||||
"Feld": 16,
|
"Feld": 16,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50011,
|
"IdLD": 50011,
|
||||||
@@ -114,7 +126,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Wasserdruck aus",
|
"Me": "Wasserdruck aus",
|
||||||
"Feld": 16,
|
"Feld": 16,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50011,
|
"IdLD": 50011,
|
||||||
@@ -123,7 +136,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Ein",
|
"Me": "Ein",
|
||||||
"Feld": 16,
|
"Feld": 16,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50011,
|
"IdLD": 50011,
|
||||||
@@ -132,7 +146,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Digitaleingang 1 ON",
|
"Me": "Digitaleingang 1 ON",
|
||||||
"Feld": 16,
|
"Feld": 16,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50000,
|
"IdLD": 50000,
|
||||||
@@ -141,7 +156,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Ein",
|
"Me": "Ein",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -150,7 +166,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Station offline",
|
"Me": "Station offline",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -159,7 +176,8 @@
|
|||||||
"Co": "#FF00FF",
|
"Co": "#FF00FF",
|
||||||
"Me": "Eingang DE 32 kommend",
|
"Me": "Eingang DE 32 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -168,7 +186,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "KÜG 07: Überspannung kommend",
|
"Me": "KÜG 07: Überspannung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -177,7 +196,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "KÜG 08: Überspannung gehend",
|
"Me": "KÜG 08: Überspannung gehend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -186,7 +206,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "KÜG 08: Überspannung gehend",
|
"Me": "KÜG 08: Überspannung gehend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -195,7 +216,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "KÜG 08: Überspannung gehend",
|
"Me": "KÜG 08: Überspannung gehend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -204,7 +226,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "Eingang DE 02 kommend",
|
"Me": "Eingang DE 02 kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -213,7 +236,8 @@
|
|||||||
"Co": "#FFFF00",
|
"Co": "#FFFF00",
|
||||||
"Me": "KÜG 08: Überspannung gehend",
|
"Me": "KÜG 08: Überspannung gehend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -222,7 +246,8 @@
|
|||||||
"Co": "#FF9900",
|
"Co": "#FF9900",
|
||||||
"Me": "Eingang DE 03 Test Karte kommend",
|
"Me": "Eingang DE 03 Test Karte kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -231,7 +256,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 01: Aderbruch kommend",
|
"Me": "KÜG 01: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -240,7 +266,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 02: Aderbruch kommend",
|
"Me": "KÜG 02: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50922,
|
"IdLD": 50922,
|
||||||
@@ -249,7 +276,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 03: Aderbruch kommend",
|
"Me": "KÜG 03: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50000,
|
"IdLD": 50000,
|
||||||
@@ -258,7 +286,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "über 8V kommend",
|
"Me": "über 8V kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -267,7 +296,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 05: Aderbruch kommend",
|
"Me": "KÜG 05: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -276,7 +306,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 02: Isolationsminderung kommend",
|
"Me": "KÜG 02: Isolationsminderung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50984,
|
"IdLD": 50984,
|
||||||
@@ -285,7 +316,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 06: Aderbruch kommend",
|
"Me": "KÜG 06: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -294,7 +326,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 01: Isolationsminderung kommend",
|
"Me": "KÜG 01: Isolationsminderung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -303,7 +336,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 06: Aderbruch kommend",
|
"Me": "KÜG 06: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50977,
|
"IdLD": 50977,
|
||||||
@@ -312,7 +346,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 05: Aderbruch kommend",
|
"Me": "KÜG 05: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50976,
|
"IdLD": 50976,
|
||||||
@@ -321,7 +356,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "CPL offline",
|
"Me": "CPL offline",
|
||||||
"Feld": 3,
|
"Feld": 3,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50976,
|
"IdLD": 50976,
|
||||||
@@ -330,7 +366,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 03: Isolationsminderung kommend",
|
"Me": "KÜG 03: Isolationsminderung kommend",
|
||||||
"Feld": 3,
|
"Feld": 3,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -339,7 +376,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 04: Isolationsminderung kommend",
|
"Me": "KÜG 04: Isolationsminderung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -348,7 +386,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 02: Isolationsminderung kommend",
|
"Me": "KÜG 02: Isolationsminderung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -357,7 +396,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 01: Isolationsminderung kommend",
|
"Me": "KÜG 01: Isolationsminderung kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50001,
|
"IdLD": 50001,
|
||||||
@@ -366,7 +406,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "Sammelstörung kommend",
|
"Me": "Sammelstörung kommend",
|
||||||
"Feld": 5,
|
"Feld": 5,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -375,7 +416,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 06: Aderbruch kommend",
|
"Me": "KÜG 06: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50975,
|
"IdLD": 50975,
|
||||||
@@ -384,7 +426,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "KÜG 05: Aderbruch kommend",
|
"Me": "KÜG 05: Aderbruch kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50963,
|
"IdLD": 50963,
|
||||||
@@ -393,7 +436,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "CPL offline",
|
"Me": "CPL offline",
|
||||||
"Feld": 3,
|
"Feld": 3,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50063,
|
"IdLD": 50063,
|
||||||
@@ -402,7 +446,8 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "Digitaleingang 1 EIN",
|
"Me": "Digitaleingang 1 EIN",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"IdLD": 50000,
|
"IdLD": 50000,
|
||||||
@@ -411,6 +456,7 @@
|
|||||||
"Co": "#FF0000",
|
"Co": "#FF0000",
|
||||||
"Me": "über 10V kommend",
|
"Me": "über 10V kommend",
|
||||||
"Feld": 4,
|
"Feld": 4,
|
||||||
"Icon": 0
|
"Icon": 0,
|
||||||
|
"Alarm": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||