import React from "react"; import type { ProfileRecord } from "../types/bluesky"; import { useColorScheme, type ColorSchemePreference, } from "../hooks/useColorScheme"; import { BlueskyIcon } from "../components/BlueskyIcon"; export interface BlueskyProfileRendererProps { record: ProfileRecord; loading: boolean; error?: Error; did: string; handle?: string; avatarUrl?: string; colorScheme?: ColorSchemePreference; } export const BlueskyProfileRenderer: React.FC = ({ record, loading, error, did, handle, avatarUrl, colorScheme = "system", }) => { const scheme = useColorScheme(colorScheme); if (error) return (
Failed to load profile.
); if (loading && !record) return
Loading…
; const palette = scheme === "dark" ? theme.dark : theme.light; const profileUrl = `https://bsky.app/profile/${encodeURIComponent(did)}`; const rawWebsite = record.website?.trim(); const websiteHref = rawWebsite ? rawWebsite.match(/^https?:\/\//i) ? rawWebsite : `https://${rawWebsite}` : undefined; const websiteLabel = rawWebsite ? rawWebsite.replace(/^https?:\/\//i, "") : undefined; return (
{avatarUrl ? ( avatar ) : (
)}
{record.displayName ?? handle ?? did}
@{handle ?? did}
{record.pronouns && (
{record.pronouns}
)}
{record.description && (

{record.description}

)} {record.createdAt && (
Joined {new Date(record.createdAt).toLocaleDateString()}
)}
{websiteHref && websiteLabel && ( {websiteLabel} )} View on Bluesky
); }; const base: Record = { card: { borderRadius: 12, padding: 16, fontFamily: "system-ui, sans-serif", maxWidth: 480, transition: "background-color 180ms ease, border-color 180ms ease, color 180ms ease", position: "relative", }, header: { display: "flex", gap: 12, marginBottom: 8, }, avatar: { width: 64, height: 64, borderRadius: "50%", }, avatarImg: { width: 64, height: 64, borderRadius: "50%", objectFit: "cover", }, display: { fontSize: 20, fontWeight: 600, }, handleLine: { fontSize: 13, }, desc: { whiteSpace: "pre-wrap", fontSize: 14, lineHeight: 1.4, }, meta: { marginTop: 12, fontSize: 12, }, pronouns: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 12, fontWeight: 500, borderRadius: 999, padding: "2px 8px", marginTop: 6, }, links: { display: "flex", flexDirection: "column", gap: 8, marginTop: 12, }, link: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 12, fontWeight: 600, textDecoration: "none", }, iconCorner: { position: "absolute", right: 12, bottom: 12, }, }; const theme = { light: { card: { border: "1px solid #e2e8f0", background: "#ffffff", color: "#0f172a", }, avatar: { background: "#cbd5e1", }, display: { color: "#0f172a", }, handleLine: { color: "#64748b", }, desc: { color: "#0f172a", }, meta: { color: "#94a3b8", }, pronouns: { background: "#e2e8f0", color: "#1e293b", }, link: { color: "#2563eb", }, }, dark: { card: { border: "1px solid #1e293b", background: "#0b1120", color: "#e2e8f0", }, avatar: { background: "#1e293b", }, display: { color: "#e2e8f0", }, handleLine: { color: "#cbd5f5", }, desc: { color: "#e2e8f0", }, meta: { color: "#a5b4fc", }, pronouns: { background: "#1e293b", color: "#e2e8f0", }, link: { color: "#38bdf8", }, }, } satisfies Record<"light" | "dark", Record>; export default BlueskyProfileRenderer;