mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-30 20:49:57 +00:00
fix auto size detection
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { ReactNode, forwardRef } from "react";
|
||||
import {cn} from "@/lib/cn.ts";
|
||||
import {isMacOS} from "@/lib/platform.ts";
|
||||
|
||||
// ConfirmDialog is the shared layout wrapper used by dialog-style window
|
||||
// surfaces (SessionExpired, SessionAboutToExpire, …). Purely a layout
|
||||
@@ -20,12 +19,12 @@ export const ConfirmDialog = forwardRef<HTMLDivElement, ConfirmDialogProps>(
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
"wails-draggable select-none flex flex-col items-center justify-center"
|
||||
"wails-draggable select-none flex flex-col items-center"
|
||||
}
|
||||
>
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("flex flex-col items-center gap-5 p-8 text-center", !isMacOS() && "pt-4")}
|
||||
className={cn("flex flex-col items-center gap-5 text-center px-8 py-6")}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useLayoutEffect, useRef } from "react";
|
||||
import { Window } from "@wailsio/runtime";
|
||||
import {isMacOS} from "@/lib/platform.ts";
|
||||
import i18next from "@/lib/i18n";
|
||||
|
||||
// useAutoSizeWindow resizes the current Wails window so its height matches
|
||||
// the measured height of the content element the returned ref is attached
|
||||
@@ -15,17 +15,42 @@ import {isMacOS} from "@/lib/platform.ts";
|
||||
// Re-measures via ResizeObserver so adding/removing content (e.g. the
|
||||
// SessionAboutToExpire title swapping at countdown zero) keeps the chrome
|
||||
// tight to the content with no scrollbar.
|
||||
//
|
||||
// Also re-measures on i18next `languageChanged`. The ResizeObserver in
|
||||
// theory catches the same reflow when translated strings replace each
|
||||
// other (DE/HU strings often wrap to more lines than EN), but in practice
|
||||
// the observer can settle on a stale size before React's commit and the
|
||||
// font's glyph metrics finish updating. An explicit double-rAF after the
|
||||
// language flip guarantees the final layout is the one we measure.
|
||||
export function useAutoSizeWindow<T extends HTMLElement>(width: number) {
|
||||
const ref = useRef<T | null>(null);
|
||||
useLayoutEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
let shown = false;
|
||||
let raf1 = 0;
|
||||
let raf2 = 0;
|
||||
const apply = () => {
|
||||
let h = Math.ceil(el.getBoundingClientRect().height);
|
||||
h = isMacOS() ? h : h - el.getBoundingClientRect().height;
|
||||
const h = Math.ceil(el.getBoundingClientRect().height);
|
||||
if (h <= 0) return;
|
||||
void Window.SetSize(width, h)
|
||||
// Wails Window.SetSize takes the *frame* size on every platform
|
||||
// (Windows: SetWindowPos, macOS: setFrame:, Linux: GTK frame).
|
||||
// The OS title bar lives inside the frame, so we have to add the
|
||||
// chrome height before calling SetSize, or the title bar eats
|
||||
// pixels from the bottom and the rendered content gets clipped.
|
||||
//
|
||||
// window.outerHeight / window.innerHeight are useless here:
|
||||
// WebView2 (and WKWebView) report the WebView's own outer == inner
|
||||
// because the WebView itself has no chrome — the OS title bar is
|
||||
// outside the WebView's window object entirely. The only way to
|
||||
// recover the chrome height is to compare the OS frame height
|
||||
// (Wails-side Window.Size()) against the WebView viewport
|
||||
// (window.innerHeight).
|
||||
void Window.Size()
|
||||
.then((frame) => {
|
||||
const chrome = Math.max(0, frame.height - window.innerHeight);
|
||||
return Window.SetSize(width, h + chrome);
|
||||
})
|
||||
.then(() => {
|
||||
if (shown) return;
|
||||
shown = true;
|
||||
@@ -34,10 +59,26 @@ export function useAutoSizeWindow<T extends HTMLElement>(width: number) {
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
// Double rAF: first frame lands after React commits the new
|
||||
// translated strings, second frame lands after the browser has
|
||||
// recomputed layout, so apply() sees the final box.
|
||||
const scheduleApply = () => {
|
||||
cancelAnimationFrame(raf1);
|
||||
cancelAnimationFrame(raf2);
|
||||
raf1 = requestAnimationFrame(() => {
|
||||
raf2 = requestAnimationFrame(apply);
|
||||
});
|
||||
};
|
||||
apply();
|
||||
const ro = new ResizeObserver(apply);
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
i18next.on("languageChanged", scheduleApply);
|
||||
return () => {
|
||||
ro.disconnect();
|
||||
cancelAnimationFrame(raf1);
|
||||
cancelAnimationFrame(raf2);
|
||||
i18next.off("languageChanged", scheduleApply);
|
||||
};
|
||||
}, [width]);
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -86,10 +86,10 @@ export default function UpdateInProgressDialog() {
|
||||
{isError ? (
|
||||
<SquareIcon
|
||||
icon={XCircle}
|
||||
className={"mt-4 bg-red-500 [&_svg]:text-white"}
|
||||
className={"bg-red-500 [&_svg]:text-white"}
|
||||
/>
|
||||
) : (
|
||||
<SquareIcon icon={Loader2} className={"mt-4 [&_svg]:animate-spin"} />
|
||||
<SquareIcon icon={Loader2} className={"[&_svg]:animate-spin"} />
|
||||
)}
|
||||
|
||||
<div className={"flex flex-col items-center gap-2"}>
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function LoginWaitingForBrowserDialog() {
|
||||
<ConfirmDialog ref={contentRef}>
|
||||
<SquareIcon
|
||||
icon={Loader2}
|
||||
className={"mt-4 [&_svg]:animate-spin"}
|
||||
className={"[&_svg]:animate-spin"}
|
||||
/>
|
||||
|
||||
<div className={"flex flex-col items-center gap-2"}>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function SessionAboutToExpireDialog() {
|
||||
|
||||
return (
|
||||
<ConfirmDialog ref={contentRef}>
|
||||
<SquareIcon icon={ClockIcon} className={"mt-4"} />
|
||||
<SquareIcon icon={ClockIcon} />
|
||||
|
||||
<div className={"flex flex-col items-center gap-1"}>
|
||||
<DialogHeading>
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function SessionExpiredDialog() {
|
||||
|
||||
return (
|
||||
<ConfirmDialog ref={contentRef}>
|
||||
<SquareIcon icon={AlertCircleIcon} className={"mt-4"} />
|
||||
<SquareIcon icon={AlertCircleIcon} />
|
||||
|
||||
<div className={"flex flex-col items-center gap-1"}>
|
||||
<DialogHeading>{t("sessionExpired.title")}</DialogHeading>
|
||||
|
||||
Reference in New Issue
Block a user