first publish
This commit is contained in:
commit
b8e41b4d55
147 files changed
+19367
No files matched your search
@@ -0,0 +1,64 @@
|
||||
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 = (
|
||||
<>
|
||||
<span className={GROW_UNDERLINE}>{label}</span>
|
||||
<span aria-hidden="true" className={ARROW}>
|
||||
{glyph}
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
const cls = cn(TEXT_LINK, className);
|
||||
|
||||
if (isInternal(href) && !external) {
|
||||
return (
|
||||
<TransitionLink href={href} label={label} className={cls}>
|
||||
{inner}
|
||||
</TransitionLink>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target={external ? "_blank" : undefined}
|
||||
rel={external ? "noopener noreferrer" : undefined}
|
||||
className={cls}
|
||||
>
|
||||
{inner}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextLink;
|
||||
Reference in new issue
Block a user