fix people

This commit is contained in:
2026-07-19 13:37:51 -05:00
parent 068debee16
commit 20960f97c0
3 changed files with 184 additions and 15 deletions

103
main.ts
View File

@@ -461,9 +461,57 @@ async function servePdfBytes(
// ------- HTTP Server -------
// ---- Webview-reported window size (fallback tracking) ----
// Both getSize() and (apparently) the native resize events are unreliable
// in the experimental desktop backend, so the frontend reports its viewport
// size via POST /api/window-metrics. The first report arrives ~800ms after
// startup, i.e. after the enforced setSize, and is used to calibrate the
// per-session offset between the outer window size and the webview viewport
// (titlebar + borders). Later reports are translated back to outer-window
// coordinates with that offset. Calibrating per session means any error
// cancels out and the window cannot shrink a little on every restart.
let webviewMetricsOffset: { dw: number; dh: number } | null = null;
let sizeSeenFromWebview = false;
Deno.serve(async (request) => {
const url = new URL(request.url);
if (url.pathname === "/api/window-metrics" && request.method === "POST") {
try {
const body = await request.json() as {
innerWidth?: number;
innerHeight?: number;
};
const iw = Math.round(Number(body.innerWidth) || 0);
const ih = Math.round(Number(body.innerHeight) || 0);
if (iw > 200 && ih > 200) {
if (webviewMetricsOffset === null) {
// First report: window is still at the enforced startup size,
// so the difference to the viewport is the decoration size.
webviewMetricsOffset = {
dw: Math.min(Math.max(clamped.windowWidth - iw, 0), 200),
dh: Math.min(Math.max(clamped.windowHeight - ih, 0), 200),
};
console.log(
`${PREFIX} Window metrics calibrated: viewport ${iw}x${ih}, decoration offset ${webviewMetricsOffset.dw}x${webviewMetricsOffset.dh}`,
);
} else {
const w = iw + webviewMetricsOffset.dw;
const h = ih + webviewMetricsOffset.dh;
if (w >= 1100 && h >= 700) {
settings.windowWidth = w;
settings.windowHeight = h;
sizeSeenFromWebview = true;
console.log(`${PREFIX} Window size (from webview): ${w}x${h}`);
}
}
}
return json({ ok: true });
} catch {
return json({ ok: false }, 400);
}
}
if (url.pathname === "/api/state" && request.method === "GET") {
const configForClient = {
jsonPath: settings.jsonPath,
@@ -710,14 +758,45 @@ if (
// Native resize tracking using Deno 2.9 BrowserWindow events
let resizeTimer: ReturnType<typeof setTimeout> | undefined;
let sizeSeenFromEvent = false;
let resizeEventLogsLeft = 3;
try {
win.addEventListener(
"resize",
((e: CustomEvent) => {
if (resizeTimer !== undefined) clearTimeout(resizeTimer);
// Store immediately but debounce writes
const w = e.detail?.width ?? 0;
const h = e.detail?.height ?? 0;
// The payload shape of the experimental backend is not settled;
// accept detail.{width,height}, detail.{w,h}, detail as [w, h],
// and width/height directly on the event object.
const anyEvent = e as unknown as Record<string, unknown>;
const detail = anyEvent.detail as
| Record<string, unknown>
| number[]
| undefined;
let w = 0;
let h = 0;
if (Array.isArray(detail)) {
w = Number(detail[0]) || 0;
h = Number(detail[1]) || 0;
} else if (detail && typeof detail === "object") {
w = Number(detail.width ?? detail.w) || 0;
h = Number(detail.height ?? detail.h) || 0;
}
if (!w) w = Number(anyEvent.width) || 0;
if (!h) h = Number(anyEvent.height) || 0;
// Log the first few raw events so we can see what the backend
// actually delivers (helps debug the unreliable size reporting).
if (resizeEventLogsLeft > 0) {
resizeEventLogsLeft--;
try {
console.log(
`${PREFIX} Native resize event: parsed=${w}x${h}, detail=${
JSON.stringify(detail)
}, event.width/height=${anyEvent.width}/${anyEvent.height}`,
);
} catch { /* ok */ }
}
if (w >= 1100 && h >= 700) {
settings.windowWidth = w;
settings.windowHeight = h;
@@ -742,12 +821,11 @@ try {
"close",
(() => {
if (resizeTimer !== undefined) clearTimeout(resizeTimer);
// Prefer the size reported by native resize events. getSize() has
// been observed to return a stale value (the last programmatically
// requested size) instead of the actual user-resized window size,
// which caused the same size to be saved on every close. Only fall
// back to getSize() if no resize event was ever received.
if (!sizeSeenFromEvent) {
// Prefer sizes reported by native resize events or by the webview.
// getSize() has been observed to return a stale value (the last
// programmatically requested size) instead of the actual window
// size, which caused the same size to be saved on every close.
if (!sizeSeenFromEvent && !sizeSeenFromWebview) {
try {
const [fw, fh] = win.getSize();
if (fw >= 1100 && fh >= 700) {
@@ -760,10 +838,11 @@ try {
const path = resolveSettingsPath();
Deno.mkdirSync(dirname(path), { recursive: true });
Deno.writeTextFileSync(path, JSON.stringify(settings, null, 2));
const source = sizeSeenFromEvent
? "resize events"
: (sizeSeenFromWebview ? "webview" : "getSize()");
console.log(
`${PREFIX} Window size saved on close: ${settings.windowWidth}x${settings.windowHeight} (source: ${
sizeSeenFromEvent ? "resize events" : "getSize()"
})`,
`${PREFIX} Window size saved on close: ${settings.windowWidth}x${settings.windowHeight} (source: ${source})`,
);
} catch (err) {
console.error(