Update-Banner: klebt oben fest (sticky), Sticky-Header rasten darunter ein
Der Hinweis "Neue Version verfuegbar" scrollte bisher weg. Jetzt sticky an der Viewport-Oberkante; das Banner meldet seine gemessene Hoehe als CSS-Var --app-banner-h, an der sich die Sticky-Header von ContractDetail/ContractForm ausrichten (top-[var(--app-banner-h,0px)]), damit sie nicht dahinter verschwinden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import { RefreshCw, X } from 'lucide-react';
|
||||
import { useVersionCheck } from '../hooks/useVersionCheck';
|
||||
|
||||
@@ -7,15 +7,47 @@ import { useVersionCheck } from '../hooks/useVersionCheck';
|
||||
* Version verfügbar ist (siehe useVersionCheck). "Jetzt neu laden" lädt die
|
||||
* Seite neu und holt damit den frischen Code; "später" blendet für die
|
||||
* laufende Session aus.
|
||||
*
|
||||
* Das Banner klebt (`sticky top-0`) an der Viewport-Oberkante, bleibt beim
|
||||
* Scrollen also stehen. Damit die seitenspezifischen Sticky-Header
|
||||
* (ContractDetail/ContractForm mit `top-[var(--app-banner-h)]`) nicht darunter
|
||||
* verschwinden, meldet das Banner seine gemessene Höhe als CSS-Variable
|
||||
* `--app-banner-h` am <html>-Element; ohne Banner ist sie 0px.
|
||||
*/
|
||||
export default function UpdateBanner() {
|
||||
const updateAvailable = useVersionCheck();
|
||||
const [dismissed, setDismissed] = useState(false);
|
||||
const barRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
if (!updateAvailable || dismissed) return null;
|
||||
const visible = updateAvailable && !dismissed;
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (!visible) {
|
||||
root.style.setProperty('--app-banner-h', '0px');
|
||||
return;
|
||||
}
|
||||
const el = barRef.current;
|
||||
if (!el) return;
|
||||
const apply = () => root.style.setProperty('--app-banner-h', `${el.offsetHeight}px`);
|
||||
apply();
|
||||
const ro = new ResizeObserver(apply);
|
||||
ro.observe(el);
|
||||
return () => {
|
||||
ro.disconnect();
|
||||
root.style.setProperty('--app-banner-h', '0px');
|
||||
};
|
||||
}, [visible]);
|
||||
|
||||
// Sicherstellen, dass die Variable auch beim Unmount zurückgesetzt wird.
|
||||
useEffect(() => () => {
|
||||
document.documentElement.style.setProperty('--app-banner-h', '0px');
|
||||
}, []);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
<div className="bg-blue-600 text-white px-6 py-2.5">
|
||||
<div ref={barRef} className="sticky top-0 z-40 bg-blue-600 text-white px-6 py-2.5">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<RefreshCw className="w-4 h-4 flex-shrink-0" />
|
||||
|
||||
@@ -1828,7 +1828,7 @@ export default function ContractDetail() {
|
||||
{/* Sticky-Header: Vertragsnummer + Kunde + Aktionsbuttons bleiben
|
||||
beim Scrollen oben stehen. -mx-8 px-8 zieht den Balken auf die
|
||||
Layout-Padding-Kante, damit's optisch bündig ist. */}
|
||||
<div className="sticky top-0 z-20 -mx-8 px-8 py-4 mb-6 bg-gray-100 border-b border-gray-200 flex items-center justify-between">
|
||||
<div className="sticky top-[var(--app-banner-h,0px)] z-20 -mx-8 px-8 py-4 mb-6 bg-gray-100 border-b border-gray-200 flex items-center justify-between">
|
||||
<div>
|
||||
<div className="flex items-center gap-4 mb-2">
|
||||
<Button
|
||||
|
||||
@@ -860,7 +860,7 @@ export default function ContractForm() {
|
||||
{/* Sticky-Header: Zurück-Button + Titel + Kunde-Zeile bleiben beim
|
||||
Scrollen oben stehen. Layout-Padding wird per -mx-8 px-8
|
||||
überbrückt, damit der Balken bündig ist. */}
|
||||
<div className="sticky top-0 z-20 -mx-8 px-8 pt-4 pb-3 mb-6 bg-gray-100 border-b border-gray-200">
|
||||
<div className="sticky top-[var(--app-banner-h,0px)] z-20 -mx-8 px-8 pt-4 pb-3 mb-6 bg-gray-100 border-b border-gray-200">
|
||||
<div className="flex items-center gap-4 mb-2">
|
||||
<Button variant="ghost" size="sm" onClick={() => navigate(back.to, { state: back.state })}>
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
|
||||
Reference in New Issue
Block a user