Author
Avatar and name.
ada grace
Code
Copy into src/components/ph/ .
Author.astro
---
type Props = {
name: string;
avatar?: string;
href?: string;
size?: "sm"| "md";
class?: string;
};
const { name, avatar, href, size = "md", class: className } = Astro.props;
const Tag = href ? "a": "span";
const px = size === "sm"? 16 : 28;
---
<Tag
href={href}
class:list={[
"inline-flex items-center gap-2 font-pixel uppercase no-underline",
size === "sm"? "gap-1.5 text-[11px] tracking-wide": "text-sm",
href && "hover:underline",
className,
]}
>
{
avatar ? (
<img src={avatar} width={px} height={px} alt="" class="shrink-0 border border-foreground" loading="lazy" decoding="async"/>
) : (
<span class="shrink-0 border border-foreground bg-ph-yellow" style={`width:${px}px;height:${px}px`} />
)
}
{name}
</Tag>
Copy into components/ph/ (or src/components/ph/).
author.tsx
import { cn } from "./cn";
type AuthorProps = {
name: string;
avatar?: string;
href?: string;
size?: "sm"| "md";
className?: string;
};
export function Author({ name, avatar, href, size = "md", className }: AuthorProps) {
const px = size === "sm"? 16 : 28;
const classes = cn(
"inline-flex items-center gap-2 font-pixel uppercase no-underline",
size === "sm"? "gap-1.5 text-[11px] tracking-wide": "text-sm",
href && "hover:underline",
className,
);
const inner = (
<>
{avatar ? (
<img src={avatar} width={px} height={px} alt="" className="shrink-0 border border-foreground" loading="lazy" decoding="async"/>
) : (
<span className="shrink-0 border border-foreground bg-ph-yellow" style={{ width: px, height: px }} />
)}
{name}
</>
);
return href ? (
<a href={href} className={classes}>
{inner}
</a>
) : (
<span className={classes}>{inner}</span>
);
}
cn.ts
export const cn = (...parts: (string | false | null | undefined)[]) => parts.filter(Boolean).join(" ");