TopBar-Redesign: Marke, Zoom-Cluster, Datei-Menü, Fenstersteuerung, Dark-Theme fest
- Marke (DOSSIER-Wortmarke) + Ressourcen-Icon ganz links, wie im Rhino-Plugin; Settings-Icon folgt über den neuen Einstellungs-Dialog. - Massstab/Zoom-Cluster bereinigt: doppelte Massstab-Dropdown entfernt, Zoom-Aktionen unter dem Massstab-Dropdown gestapelt (gleiche Breite), Ring bei "am Massstab" statt Flächen-Aufhellung. - PDF/DXF-Export aus der Leiste raus, zusammen mit Speichern/Öffnen/ Import in einem neuen Datei-Burger-Menü ganz rechts. Speichern/Öffnen sind echte JSON-Download/-Upload-Handler fürs ganze Projekt. - Einstellungs-Fenster (neu): Accent-Palette, Auswahlrahmen-/Snap-Farbe editierbar (freier Picker + Presets), Projekt-Referenzhöhe (m ü. M.) als Feld. - LayoutMenu auf die eigene Dropdown-Komponente umgestellt (war noch natives <select>). - Custom Fenstersteuerung (_/□/X) für die randlose Electron-Shell via Preload+IPC, eigener Look statt OS-Chrome; Oberleiste als Drag-Region. - Dark-Theme ist jetzt fester Standard (vorher an OS-Präferenz gekoppelt, zeigte je nach Umgebung fälschlich Light) — Light bleibt als Opt-in (`[data-theme="light"]`) für einen künftigen Umschalter. Alle Oberleisten-Pillen (Dropdown-Trigger, Segmente, Icon-Knöpfe, Ansichts-Icons) auf dieselbe dunkle Fläche wie das Kontextmenü vereinheitlicht. Panel-Köpfe nicht mehr separat aufgehellt, feste Höhe (40px) unabhängig von optionalem Darstellungsmodus-Dropdown. - 2D-Zoom-Grenzen deutlich erweitert (20000x/0.005x statt 50x/0.2x).
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
// Eigene Fenstersteuerung (Minimieren/Maximieren/Schliessen) für das randlose
|
||||
// Electron-Fenster (frame:false, s. scripts/electron-main.cjs) — ohne native
|
||||
// Titelleiste gibt es sonst keine Möglichkeit, das Fenster zu steuern.
|
||||
//
|
||||
// Rendert NUR, wenn `window.dossierWindow` existiert (vom Preload-Skript
|
||||
// injiziert) — also nur unter Electron. In Tauri (native Fensterdekoration)
|
||||
// und im Browser-Dev-Modus (?vite) bleibt die Komponente unsichtbar (`null`),
|
||||
// dort steuert das Betriebssystem bzw. der Browser das Fenster.
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
/** Von electron-preload.cjs via contextBridge injiziert (nur unter Electron). */
|
||||
interface DossierWindowApi {
|
||||
minimize: () => void;
|
||||
toggleMaximize: () => void;
|
||||
close: () => void;
|
||||
isMaximized: () => Promise<boolean>;
|
||||
onMaximizedChange: (callback: (isMaximized: boolean) => void) => () => void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
dossierWindow?: DossierWindowApi;
|
||||
}
|
||||
}
|
||||
|
||||
export function WindowControls() {
|
||||
const api = window.dossierWindow;
|
||||
const [maximized, setMaximized] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!api) return;
|
||||
let cancelled = false;
|
||||
api.isMaximized().then((v) => {
|
||||
if (!cancelled) setMaximized(v);
|
||||
});
|
||||
const unsubscribe = api.onMaximizedChange((v) => setMaximized(v));
|
||||
return () => {
|
||||
cancelled = true;
|
||||
unsubscribe();
|
||||
};
|
||||
}, [api]);
|
||||
|
||||
if (!api) return null;
|
||||
|
||||
return (
|
||||
<div className="win-controls" role="group" aria-label="Fenster">
|
||||
<button
|
||||
type="button"
|
||||
className="win-btn"
|
||||
onClick={() => api.minimize()}
|
||||
title="Minimieren"
|
||||
aria-label="Minimieren"
|
||||
>
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path d="M1 5 L9 5" stroke="currentColor" strokeWidth="1.2" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="win-btn"
|
||||
onClick={() => api.toggleMaximize()}
|
||||
title={maximized ? "Wiederherstellen" : "Maximieren"}
|
||||
aria-label={maximized ? "Wiederherstellen" : "Maximieren"}
|
||||
>
|
||||
{maximized ? (
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path
|
||||
d="M2.5 1.5 H8.5 V7.5 H2.5 Z M2.5 1.5 V3 M1.5 3 H2.5 M1.5 3 V9 H7.5 V7.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
||||
<rect
|
||||
x="1.5"
|
||||
y="1.5"
|
||||
width="7"
|
||||
height="7"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="win-btn win-btn-close"
|
||||
onClick={() => api.close()}
|
||||
title="Schliessen"
|
||||
aria-label="Schliessen"
|
||||
>
|
||||
<svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
|
||||
<path
|
||||
d="M1 1 L9 9 M9 1 L1 9"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user