import { cn } from "@/lib/utils"; import { TransitionLink } from "@/components/motion/TransitionLink"; export interface TextLinkProps { href: string; label: string; /** `target="_blank" rel="noopener noreferrer"` + ↗ instead of →. */ external?: boolean; /** Anchor/arrow glyph override (default → / ↗ / ↓ for `#…`). */ arrow?: string; className?: string; } /** Caps text link style (Jost 500, 13 px, ls .2em) – shared with ledger links. * `-my-4/py-4` grows the tap target to 45 px without moving the baseline. */ export const TEXT_LINK = "group/tl -my-4 inline-flex items-baseline gap-2 py-4 font-sans text-[0.8125rem] font-medium uppercase leading-none tracking-[0.2em] text-accent"; /** Underline grows from the left (`background-size 0 → 100%`, 0.4 s). */ export const GROW_UNDERLINE = "bg-[linear-gradient(currentColor,currentColor)] bg-[length:0%_1px] bg-left-bottom bg-no-repeat pb-1 transition-[background-size] duration-[400ms] ease-[var(--ease-out-quart)] group-hover/tl:bg-[length:100%_1px] group-focus-visible/tl:bg-[length:100%_1px]"; const ARROW = "transition-transform duration-300 ease-[var(--ease-out-quart)] group-hover/tl:translate-x-2"; function isInternal(href: string) { return href.startsWith("/"); } /** * Caps link with an arrow glyph. Internal routes go through the curtain * (`TransitionLink`); mailto/tel/http are plain anchors. */ export function TextLink({ href, label, external = false, arrow, className }: TextLinkProps) { const glyph = arrow ?? (external ? "↗" : href.startsWith("#") ? "↓" : "→"); const inner = ( <> {label} ); const cls = cn(TEXT_LINK, className); if (isInternal(href) && !external) { return ( {inner} ); } return ( {inner} ); } export default TextLink;