Fourteen commits since v0.13.0. See CHANGELOG.md for the full list. Two additions: `npm run doctor`, which runs the config doctor from a terminal — including inside the shipped image — and exits with the worst finding, so it can gate a deployment script; and a Playwright spec that loads all fourteen admin routes against a production build. One change, invisible on screen: the admin panel got a form-field layer (#533). Five fixes: grid.gap on both axes (#513), the dashboard status badge (#539), the journal editor's unsaved-changes guard (#538), essay paragraph markup (#537), and aria-pressed on the panel's switches and pickers.
30 lines
1.1 KiB
TypeScript
30 lines
1.1 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
|
|
/**
|
|
* Asks the browser to confirm before leaving while `dirty` is true.
|
|
*
|
|
* The page builder and the settings editor each carried their own copy of this
|
|
* effect, byte for byte. The journal studio tracked `dirty` and had none, so
|
|
* closing the tab mid-entry lost the work without a word while the same action
|
|
* in the other two editors asked first (#538). A third copy would have been the
|
|
* third chance to forget it.
|
|
*
|
|
* `returnValue` is set as well as `preventDefault()`: the property is what older
|
|
* browsers read, and Safari still needs it. No custom string is passed because
|
|
* no browser has shown one for years — the text is the browser's own.
|
|
*/
|
|
export function useUnsavedGuard(dirty: boolean) {
|
|
useEffect(() => {
|
|
function handleBeforeUnload(e: BeforeUnloadEvent) {
|
|
if (dirty) {
|
|
e.preventDefault();
|
|
e.returnValue = '';
|
|
}
|
|
}
|
|
window.addEventListener('beforeunload', handleBeforeUnload);
|
|
return () => window.removeEventListener('beforeunload', handleBeforeUnload);
|
|
}, [dirty]);
|
|
}
|