feat(kue705FO): scrolling für lange Modulnamen (48 Zeichen) + Version-Gate/Env-Override
- Unterstützt bis zu 48 Zeichen im Modulnamen; bei Überlänge automatische Laufschrift - Marquee via react-fast-marquee (SSR-sicher per next/dynamic) - Overflow-Erkennung + Tooltip mit vollem Namen - Version-Gate: aktiviert ab V4.30
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
"use client"; // components/modules/kue705FO/Kue705FO.tsx
|
||||
import React, { useState, useMemo } from "react";
|
||||
import React, { useState, useMemo, useEffect, useRef } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const Marquee: any = dynamic(() => import("react-fast-marquee"), {
|
||||
ssr: false,
|
||||
});
|
||||
import { useSelector } from "react-redux";
|
||||
import KueModal from "./modals/SettingsModalWrapper";
|
||||
// import FallSensors from "../../fall-detection-sensors/FallSensors";
|
||||
@@ -54,6 +59,19 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
||||
// Admin authentication hook for security - using showModal as true for continuous auth check
|
||||
const { isAdminLoggedIn } = useAdminAuth(true);
|
||||
|
||||
// Modulname (max 48 Zeichen) vorbereiten
|
||||
const moduleNameRaw = useMemo(
|
||||
() => kueName?.[slotIndex] || `Modul ${slotIndex + 1}`,
|
||||
[kueName, slotIndex]
|
||||
);
|
||||
const moduleName48 = useMemo(
|
||||
() =>
|
||||
typeof moduleNameRaw === "string"
|
||||
? moduleNameRaw.slice(0, 48)
|
||||
: String(moduleNameRaw),
|
||||
[moduleNameRaw]
|
||||
);
|
||||
|
||||
const [activeButton, setActiveButton] = useState<"Schleife" | "TDR" | "ISO">(
|
||||
"Schleife"
|
||||
);
|
||||
@@ -206,6 +224,53 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
||||
);
|
||||
const { setCurrentModulName } = useModulName(slotIndex, modulName);
|
||||
//---------------------------------
|
||||
// Version-gate für Laufschrift: erst ab V4.30 aktiv
|
||||
const parseVersion = (v?: string): [number, number, number] => {
|
||||
if (!v) return [0, 0, 0];
|
||||
const m = String(v).match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
||||
if (!m) return [0, 0, 0];
|
||||
const major = parseInt(m[1] || "0", 10) || 0;
|
||||
const minor = parseInt(m[2] || "0", 10) || 0;
|
||||
const patch = parseInt(m[3] || "0", 10) || 0;
|
||||
return [major, minor, patch];
|
||||
};
|
||||
const gte = (a: [number, number, number], b: [number, number, number]) => {
|
||||
if (a[0] !== b[0]) return a[0] > b[0];
|
||||
if (a[1] !== b[1]) return a[1] > b[1];
|
||||
return a[2] >= b[2];
|
||||
};
|
||||
const marqueeOverride =
|
||||
process.env.NEXT_PUBLIC_ENABLE_KUE_MARQUEE === "1" ||
|
||||
process.env.NEXT_PUBLIC_ENABLE_KUE_MARQUEE === "true";
|
||||
const scrollFeatureEnabled = useMemo(
|
||||
() => marqueeOverride || gte(parseVersion(kueVersion), [4, 30, 0]),
|
||||
[kueVersion, marqueeOverride]
|
||||
);
|
||||
|
||||
// Überlängen-Erkennung für Laufschrift
|
||||
const nameContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const measureTextRef = useRef<HTMLSpanElement | null>(null);
|
||||
const [shouldScroll, setShouldScroll] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const measure = () => {
|
||||
if (!scrollFeatureEnabled) {
|
||||
setShouldScroll(false);
|
||||
return;
|
||||
}
|
||||
const container = nameContainerRef.current;
|
||||
const text = measureTextRef.current;
|
||||
if (!container || !text) {
|
||||
setShouldScroll(false);
|
||||
return;
|
||||
}
|
||||
const needs = text.scrollWidth > container.clientWidth + 2;
|
||||
setShouldScroll(needs);
|
||||
};
|
||||
measure();
|
||||
window.addEventListener("resize", measure);
|
||||
return () => window.removeEventListener("resize", measure);
|
||||
}, [moduleName48, scrollFeatureEnabled]);
|
||||
//---------------------------------
|
||||
const tdmChartData = useSelector(
|
||||
(state: RootState) => state.tdmChartSlice.data
|
||||
@@ -360,8 +425,38 @@ const Kue705FO: React.FC<Kue705FOProps> = ({
|
||||
<div className="absolute top-0 left-[4.688rem] w-[0.188rem] h-full bg-white z-0"></div>
|
||||
<div className="absolute top-[2.5rem] left-[4.688rem] w-[2.5rem] h-[0.188rem] bg-white z-0"></div>
|
||||
|
||||
<div className="absolute bottom-[1.25rem] left-0 right-0 text-black text-[0.625rem] bg-gray-300 p-[0.063rem] text-center">
|
||||
{kueName?.[slotIndex] || `Modul ${slotIndex + 1}`}
|
||||
{/* Hidden measuring span for overflow detection (kept measurable) */}
|
||||
<span
|
||||
ref={measureTextRef}
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: -9999,
|
||||
top: -9999,
|
||||
visibility: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
>
|
||||
{moduleName48}
|
||||
</span>
|
||||
|
||||
<div
|
||||
ref={nameContainerRef}
|
||||
className="absolute bottom-[1.25rem] left-0 right-0 text-black text-[0.625rem] bg-gray-300 p-[0.063rem] overflow-hidden"
|
||||
>
|
||||
{shouldScroll && scrollFeatureEnabled ? (
|
||||
<Marquee pauseOnHover gradient={false} speed={40}>
|
||||
<span className="pr-8 whitespace-nowrap" title={moduleName48}>
|
||||
{moduleName48}
|
||||
</span>
|
||||
</Marquee>
|
||||
) : (
|
||||
<span
|
||||
className="block text-center whitespace-nowrap"
|
||||
title={moduleName48}
|
||||
>
|
||||
{moduleName48}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-[0.063rem] right-[0.063rem] text-black text-[0.5rem]">
|
||||
|
||||
Reference in New Issue
Block a user