diff --git a/src/renderer/components/Layout/MenuBar.tsx b/src/renderer/components/Layout/MenuBar.tsx index 778dcc72..cf947b93 100644 --- a/src/renderer/components/Layout/MenuBar.tsx +++ b/src/renderer/components/Layout/MenuBar.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState, useSyncExternalStore, type ChangeEvent } from 'react' +import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore, type ChangeEvent } from 'react' import { BarChart3, Boxes, @@ -570,12 +570,19 @@ export const MenuBar = ({ -
+
{t('app.title', 'Cable Planner')} │ + {/* Die fuenf Menues in EINER Gruppe (B-77) — sie ist es, die auf + schmalen Fenstern rollt, und nicht die ganze Kopfzeile. Rollte die + Zeile, rollte der Einstellungen-Knopf rechts mit aus dem Bild, und + genau das verhindert der Kommentar weiter unten seit B-66. + Dieselbe Bauart wie `.bc-menubar` im `multicam-planner` und + `.tb-menubar` im `light-planner`. */} +
} shortcut={t('shortcut.ctrlN', 'Ctrl+N')}> {t('app.menu.file.new', 'New project')} @@ -1145,6 +1152,7 @@ export const MenuBar = ({ {t('app.menu.help.about', 'About Cable Planner…')} +
@@ -1250,6 +1258,10 @@ interface MenuProps { const Menu = ({ label, children }: MenuProps) => { const [open, setOpen] = useState(false) const ref = useRef(null) + const knopf = useRef(null) + const klappe = useRef(null) + /** Das Rechteck des angeklickten Titels — Ausgangspunkt der Klappe. */ + const [anker, setAnker] = useState<{ links: number; oben: number } | null>(null) useEffect(() => { if (!open) return @@ -1261,14 +1273,52 @@ const Menu = ({ label, children }: MenuProps) => { const onKey = (event: KeyboardEvent) => { if (event.key === 'Escape') setOpen(false) } + // ROLLEN FUEHRT NACH, GROESSE SCHLIESST (B-77). Die Menue-Gruppe rollt + // auf schmalen Fenstern waagerecht, also bewegt sich der Titel — und die + // Klappe haengt seit B-77 am Fenster und merkt das nicht von selbst. + // Schliessen beim Rollen waere falsch: liegt ein Titel ausserhalb der + // Leiste, rollt ein Klick sie erst dorthin, und das Rollereignis kommt + // NACH dem Klick. Im `multicam-planner` ging die Klappe damit auf und + // sofort wieder zu (gemessen bei 390 px). + const nachfuehren = () => { + const r = knopf.current?.getBoundingClientRect() + if (r) setAnker({ links: r.left, oben: r.bottom + 4 }) + } + const zu = () => setOpen(false) document.addEventListener('mousedown', onDocClick) document.addEventListener('keydown', onKey) + window.addEventListener('resize', zu) + window.addEventListener('scroll', nachfuehren, true) return () => { document.removeEventListener('mousedown', onDocClick) document.removeEventListener('keydown', onKey) + window.removeEventListener('resize', zu) + window.removeEventListener('scroll', nachfuehren, true) } }, [open]) + // B-77 — DIE KLAPPE HAENGT AM FENSTER, NICHT AN DER LEISTE. + // + // Sie war ein `absolute`-Kind der Kopfzeile. Solange nichts abschneidet, + // faellt das nicht auf; sobald ein Vorfahr rollt, ist die Klappe weg. Im + // `light-planner` ist genau das passiert: ein `overflow: hidden`, das die + // Kopfzeile einzeilig halten sollte, machte aus einer 250 x 505 px grossen + // Datei-Klappe eine mit 0 px sichtbarer Flaeche — vier Menues, kein + // einziges ging auf. + // + // Gemessen wird NACH dem Einhaengen: die Breite haengt am laengsten + // Eintrag und ist auf Deutsch eine andere als auf Englisch. + useLayoutEffect(() => { + const el = klappe.current + if (!el || !anker) return + const r = el.getBoundingClientRect() + const rand = 8 + const links = Math.max(rand, Math.min(anker.links, window.innerWidth - rand - r.width)) + const oben = Math.max(rand, Math.min(anker.oben, window.innerHeight - rand - r.height)) + el.style.left = `${links}px` + el.style.top = `${oben}px` + }, [anker, open]) + // #461 — Tastatur-Navigation im offenen Menue: beim Oeffnen ersten Eintrag // fokussieren, Pfeile/Home/End bewegen den Fokus zwischen den menuitems. useEffect(() => { @@ -1311,10 +1361,15 @@ const Menu = ({ label, children }: MenuProps) => { } return ( -
+