- );
-}
+// Lightbox extracted to ./Lightbox.tsx so the settings avatar preview and
+// any future surface can reuse the same dialog without duplication.
diff --git a/apps/desktop/src/components/Lightbox.tsx b/apps/desktop/src/components/Lightbox.tsx
new file mode 100644
index 0000000..9c7a07f
--- /dev/null
+++ b/apps/desktop/src/components/Lightbox.tsx
@@ -0,0 +1,51 @@
+import { useEffect } from 'react';
+
+import { XIcon } from './icons';
+
+// Fullscreen image viewer. Backdrop click + Esc close. Originally lived
+// inside AttachmentImage.tsx as a file-private component; extracted here
+// so other surfaces (settings avatar preview, future profile popover,
+// etc.) can reuse the exact same dialog without duplicating the chrome.
+//
+// The image itself stops click propagation so a click on the picture
+// keeps the lightbox open — only the backdrop or the explicit close
+// button dismisses.
+export function Lightbox({ url, onClose }: { url: string; onClose: () => void }) {
+ useEffect(() => {
+ function onKey(e: KeyboardEvent) {
+ if (e.key === 'Escape') onClose();
+ }
+ document.addEventListener('keydown', onKey);
+ const prevOverflow = document.body.style.overflow;
+ document.body.style.overflow = 'hidden';
+ return () => {
+ document.removeEventListener('keydown', onKey);
+ document.body.style.overflow = prevOverflow;
+ };
+ }, [onClose]);
+
+ return (
+