Files
photos/web/useContainerWidth.ts
pastilhasandClaude Opus 5 2dad1907f8 photos, extracted from the platform into its own repository
The fifth plugin out, and the cheapest so far — offscale's shape rather than
music's or vault's. Nothing stayed behind and nothing had to be redesigned,
for three structural reasons recorded in PLUGIN.md:

  • No reverse dependency. Nothing in src/ imported anything of photos'.
  • Configuration was already right. The URL and API key live in photos_config,
    a per-user registry encrypted at rest and driven from the app. Vault had to
    move VAULTWARDEN_URL out of .env and invent a settings panel; here the
    sidecar already read the database, and its own comment already said why
    nothing reads process.env.
  • The frontend was already panels. The screen was a WorkspaceView around
    exactly photos-nav and photos-view, so web/panels.ts and web/layout.ts are
    the screen's contents with the wrapper removed.

The router's prefix is now derived from mountPrefix rather than the literal
'/api/photos', which was correct only by coincidence — a third-party publisher
mounts at /api/p/<publisher>/photos and the literal would forward the wrong
path to the sidecar.

Palette debt paid down as the runbook requires: 6 classes (it says 47; someone
had already done most of it), all of them state colours wearing palette
numbers, now `success` and `warning` from the closed tone set so they follow
the theme.

Immich itself is still provisioned by the app store rather than by this plugin
— the `provisioned` half of its old catalogue entry has no home until Docker
provisioning for plugins exists. Point it at an instance you already run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:10:39 +00:00

29 lines
989 B
TypeScript

import { useLayoutEffect, useRef, useState } from 'react';
/**
* Measure an element's inner width and keep it current.
*
* The justified grid needs a real pixel width before it can lay anything out, and panels here are resized by
* dragging a splitter — a width read once on mount is wrong within seconds. ResizeObserver rather than a
* window resize listener for exactly that reason: the window never changes size, the panel does.
*/
export function useContainerWidth<T extends HTMLElement>() {
const ref = useRef<T | null>(null);
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
const el = ref.current;
if (!el) return;
setWidth(el.clientWidth);
const observer = new ResizeObserver((entries) => {
const next = entries[0]?.contentRect.width ?? 0;
setWidth((prev) => (Math.abs(prev - next) < 1 ? prev : next));
});
observer.observe(el);
return () => observer.disconnect();
}, []);
return [ref, width] as const;
}