~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
40 lines · 1.4 KB Raw History
import { useState } from 'react';
import { cn } from '#/lib/utils.js';

/**
 * A square app tile. A borderless rounded frame keeps every app icon the same
 * shape while the favicon, of whatever shape or transparency, sits centered
 * within it. The source is asked to 404 rather than serve a placeholder when it
 * has no icon (`fallback=false`), so a genuinely iconless domain falls through
 * to a clean initial instead of a generic glyph. Resolved client-side, so it
 * needs no endpoint. `domain` is a registrable host like `bsky.app`; `label`
 * seeds the fallback letter when there is no domain.
 */
export function AppTile({ domain, label, size = 40, className }) {
  const [broken, setBroken] = useState(false);
  const letter = (label || domain || '?').slice(0, 1).toUpperCase();
  const showIcon = domain && !broken;

  return (
    <div
      className={cn(
        'flex shrink-0 items-center justify-center overflow-hidden rounded-xl bg-muted font-extrabold text-muted-foreground',
        className,
      )}
      style={{ width: size, height: size, fontSize: Math.round(size * 0.42) }}
    >
      {showIcon ? (
        <img
          src={`https://unavatar.io/${encodeURIComponent(domain)}?fallback=false`}
          alt=""
          width={Math.round(size * 0.62)}
          height={Math.round(size * 0.62)}
          className="object-contain"
          onError={() => setBroken(true)}
        />
      ) : (
        letter
      )}
    </div>
  );
}