Added ldap and pam authentication
This commit is contained in:
+76
-5
@@ -1,24 +1,95 @@
|
||||
import { h } from 'preact';
|
||||
import { useState } from 'preact/hooks';
|
||||
import { useEffect, useState } from 'preact/hooks';
|
||||
|
||||
const LS_KEY = 'uopi:ui-zoom';
|
||||
const ZOOM_EVENT = 'uopi:zoomchange';
|
||||
const STEPS = [0.5, 0.6, 0.75, 0.85, 1.0, 1.15, 1.3, 1.5, 1.75, 2.0, 2.5];
|
||||
|
||||
// serverDefaultZoom is the base scale configured server-side ([ui] default_zoom),
|
||||
// pushed in once /me resolves. It is the fallback when this browser has no saved
|
||||
// per-machine override, so a fresh client on a HiDPI screen starts enlarged
|
||||
// without per-browser setup while a user's local A+/A− choice still wins.
|
||||
let serverDefaultZoom = 1;
|
||||
|
||||
// hasStoredZoom reports whether this browser has an explicit saved zoom override.
|
||||
export function hasStoredZoom(): boolean {
|
||||
return localStorage.getItem(LS_KEY) !== null;
|
||||
}
|
||||
|
||||
// setServerDefaultZoom records the server default and, unless the user has a saved
|
||||
// override, applies it immediately (without persisting, so a later server change
|
||||
// still propagates).
|
||||
export function setServerDefaultZoom(z: number): void {
|
||||
serverDefaultZoom = isFinite(z) && z > 0 ? z : 1;
|
||||
if (!hasStoredZoom()) {
|
||||
applyZoom(serverDefaultZoom, false);
|
||||
}
|
||||
}
|
||||
|
||||
export function getStoredZoom(): number {
|
||||
const v = parseFloat(localStorage.getItem(LS_KEY) ?? '1');
|
||||
const raw = localStorage.getItem(LS_KEY);
|
||||
const v = raw === null ? serverDefaultZoom : parseFloat(raw);
|
||||
return isFinite(v) ? Math.max(STEPS[0], Math.min(STEPS[STEPS.length - 1], v)) : 1;
|
||||
}
|
||||
|
||||
export function applyZoom(z: number): number {
|
||||
// dprFactor returns the device-pixel-ratio scaling applied on top of the manual
|
||||
// zoom so the UI is proportionally larger on high-DPI displays by default.
|
||||
// Firefox only honours CSS rem scaling (it does not auto-enlarge the root px the
|
||||
// way Chrome does on some setups), so the ratio must be folded into the root
|
||||
// font-size explicitly rather than left to the browser.
|
||||
export function dprFactor(): number {
|
||||
const dpr = window.devicePixelRatio;
|
||||
return isFinite(dpr) && dpr > 0 ? dpr : 1;
|
||||
}
|
||||
|
||||
// applyZoom sets the root font-size to scale the whole UI. When persist is true
|
||||
// (a deliberate user action) the choice is saved as this browser's override;
|
||||
// pass false to apply the server default transiently. A ZOOM_EVENT is dispatched
|
||||
// so the ZoomControl's displayed percentage stays in sync regardless of source.
|
||||
export function applyZoom(z: number, persist = true): number {
|
||||
const clamped = Math.max(STEPS[0], Math.min(STEPS[STEPS.length - 1], z));
|
||||
localStorage.setItem(LS_KEY, String(clamped));
|
||||
document.documentElement.style.fontSize = `${Math.round(16 * clamped)}px`;
|
||||
if (persist) {
|
||||
localStorage.setItem(LS_KEY, String(clamped));
|
||||
}
|
||||
const dpr = dprFactor();
|
||||
document.documentElement.style.setProperty('--dpr', String(dpr));
|
||||
document.documentElement.style.fontSize = `${Math.round(16 * clamped * dpr)}px`;
|
||||
window.dispatchEvent(new CustomEvent(ZOOM_EVENT, { detail: clamped }));
|
||||
return clamped;
|
||||
}
|
||||
|
||||
// watchDpr re-applies the current zoom whenever the device-pixel-ratio changes
|
||||
// (e.g. the window moves to a monitor with different scaling). matchMedia fires
|
||||
// once per resolution change; the listener is re-armed each time. Returns an
|
||||
// unsubscribe function.
|
||||
export function watchDpr(): () => void {
|
||||
let mql: MediaQueryList | null = null;
|
||||
const onChange = () => {
|
||||
// Re-apply at the new DPR; only persist if this browser actually has an
|
||||
// override (otherwise a monitor change would freeze the server default).
|
||||
applyZoom(getStoredZoom(), hasStoredZoom());
|
||||
arm();
|
||||
};
|
||||
const arm = () => {
|
||||
mql?.removeEventListener('change', onChange);
|
||||
mql = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
|
||||
mql.addEventListener('change', onChange);
|
||||
};
|
||||
arm();
|
||||
return () => mql?.removeEventListener('change', onChange);
|
||||
}
|
||||
|
||||
export default function ZoomControl() {
|
||||
const [zoom, setZoom] = useState(getStoredZoom);
|
||||
|
||||
// Keep the displayed percentage in sync when zoom is applied from elsewhere
|
||||
// (e.g. the server default arriving via /me, or a DPR change).
|
||||
useEffect(() => {
|
||||
const onZoom = (e: Event) => setZoom((e as CustomEvent<number>).detail);
|
||||
window.addEventListener(ZOOM_EVENT, onZoom);
|
||||
return () => window.removeEventListener(ZOOM_EVENT, onZoom);
|
||||
}, []);
|
||||
|
||||
function step(dir: number) {
|
||||
const idx = STEPS.findIndex(s => s >= zoom - 0.01);
|
||||
const nextIdx = Math.max(0, Math.min(STEPS.length - 1, idx + dir));
|
||||
|
||||
Reference in New Issue
Block a user