feat: optimize profile image sizes, silent PWA updates, storage cleanup fixes
- Resize avatars/icons to 256px and banners to 1280px (client crop + server safety net) - Add server-side resizeProfileImage() for federation/API uploads without crop modal - Fix unconstrained crop on RegisterPage and CreateSpace (was missing maxOutputDimension) - PWA: switch to autoUpdate with skipWaiting/clientsClaim for seamless deploys - Storage janitor: exclude profile images from unlinked cleanup, delete stale thumbnails - Add deleteAttachmentByFilename() to clean orphaned attachment records for profile images - Migration: one-time cleanup of stale profile image attachment records - GeneralPanel: wrap in <form> to prevent implicit submission
This commit is contained in:
@@ -473,6 +473,7 @@ export function RegisterPage() {
|
||||
title="Crop Avatar"
|
||||
aspectRatio={1}
|
||||
cropShape="round"
|
||||
maxOutputDimension={256}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -300,6 +300,7 @@ export function CreateSpaceModal() {
|
||||
title="Crop Space Icon"
|
||||
cropShape="round"
|
||||
aspectRatio={1}
|
||||
maxOutputDimension={256}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ export function GeneralPanel() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<form className="space-y-5" onSubmit={(e) => e.preventDefault()}>
|
||||
<div className="text-xs text-txt-tertiary">
|
||||
Configure your Backspace instance. These settings affect all users.
|
||||
</div>
|
||||
@@ -178,6 +178,6 @@ export function GeneralPanel() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -741,7 +741,7 @@ export function AccountPanel() {
|
||||
title="Crop Avatar"
|
||||
cropShape="round"
|
||||
aspectRatio={1}
|
||||
maxOutputDimension={512}
|
||||
maxOutputDimension={256}
|
||||
/>
|
||||
<ImageCropModal
|
||||
isOpen={bannerCropSrc !== null}
|
||||
@@ -751,7 +751,7 @@ export function AccountPanel() {
|
||||
title="Crop Banner"
|
||||
cropShape="rect"
|
||||
aspectRatio={3}
|
||||
maxOutputDimension={1920}
|
||||
maxOutputDimension={1280}
|
||||
/>
|
||||
|
||||
<DeleteAccountModal
|
||||
|
||||
@@ -601,7 +601,7 @@ export function OverviewPanel({ spaceId }: OverviewPanelProps) {
|
||||
title="Crop Space Icon"
|
||||
cropShape="round"
|
||||
aspectRatio={1}
|
||||
maxOutputDimension={512}
|
||||
maxOutputDimension={256}
|
||||
/>
|
||||
|
||||
<ImageCropModal
|
||||
@@ -612,7 +612,7 @@ export function OverviewPanel({ spaceId }: OverviewPanelProps) {
|
||||
title="Crop Space Banner"
|
||||
cropShape="rect"
|
||||
aspectRatio={16 / 9}
|
||||
maxOutputDimension={1920}
|
||||
maxOutputDimension={1280}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { useRegisterSW } from 'virtual:pwa-register/react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function SwUpdatePrompt() {
|
||||
const {
|
||||
needRefresh: [needRefresh],
|
||||
updateServiceWorker,
|
||||
} = useRegisterSW();
|
||||
export function SwAutoUpdate() {
|
||||
useRegisterSW({
|
||||
onRegisteredSW(_swUrl, registration) {
|
||||
if (!registration) return;
|
||||
setInterval(() => {
|
||||
registration.update();
|
||||
}, 60_000);
|
||||
},
|
||||
});
|
||||
|
||||
if (!needRefresh) return null;
|
||||
useEffect(() => {
|
||||
if (!navigator.serviceWorker) return;
|
||||
const onControllerChange = () => window.location.reload();
|
||||
navigator.serviceWorker.addEventListener('controllerchange', onControllerChange);
|
||||
return () => navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[9999] glass-pill px-4 py-2.5 flex items-center gap-3 text-sm text-txt-primary shadow-lg">
|
||||
<span>A new version is available</span>
|
||||
<button
|
||||
onClick={() => updateServiceWorker(true)}
|
||||
className="px-3 py-1 rounded-md bg-accent-primary text-white text-xs font-medium hover:opacity-90 transition-opacity"
|
||||
>
|
||||
Reload
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user