Link
Underlined inline link.
fill out the intake form or contact us
Code
Copy into src/components/ph/ .
link.css
.ph-link {
color: inherit;
text-decoration-line: underline;
text-decoration-thickness: 1px;
text-underline-offset: 3px;
text-decoration-color: var(--link, var(--rule));
padding-inline: 3px;
margin-inline: -3px;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
transition:
color 150ms var(--ph-ease),
background-color 150ms var(--ph-ease);
}
.ph-link:focus-visible,
.ph-link:hover {
color: var(--foreground);
background-color: var(--border);
}
/* Half ink keeps the tint's hue while clearing 4.5:1. */
@supports (color: color-mix(in oklab, red, red)) {
.ph-link:focus-visible,
.ph-link:hover {
color: color-mix(in oklab, var(--link, var(--foreground)) 50%, var(--foreground));
background-color: color-mix(in oklab, var(--link, var(--rule)) 15%, var(--background));
}
}
@media (hover: none) {
.ph-link:hover {
background-color: transparent;
}
}
Link.astro
---
import type { HTMLAttributes } from "astro/types";
import "./link.css";
type Props = HTMLAttributes<"a"> & {
href: string;
tint?: string;
};
const { href, tint, class: className, style, ...rest } = Astro.props;
const external = /^https?:\/\//.test(href);
---
<a
href={href}
target={external ? "_blank" : undefined}
rel={external ? "noopener noreferrer" : undefined}
data-tint={tint ? "" : undefined}
class:list={["ph-link", className]}
style={[tint && `--link: ${tint}`, style].filter(Boolean).join("; ") || undefined}
{...rest}><slot /></a
>
Copy into components/ph/ (or src/components/ph/).
link.css
.ph-link {
color: inherit;
text-decoration-line: underline;
text-decoration-thickness: 1px;
text-underline-offset: 3px;
text-decoration-color: var(--link, var(--rule));
padding-inline: 3px;
margin-inline: -3px;
box-decoration-break: clone;
-webkit-box-decoration-break: clone;
transition:
color 150ms var(--ph-ease),
background-color 150ms var(--ph-ease);
}
.ph-link:focus-visible,
.ph-link:hover {
color: var(--foreground);
background-color: var(--border);
}
/* Half ink keeps the tint's hue while clearing 4.5:1. */
@supports (color: color-mix(in oklab, red, red)) {
.ph-link:focus-visible,
.ph-link:hover {
color: color-mix(in oklab, var(--link, var(--foreground)) 50%, var(--foreground));
background-color: color-mix(in oklab, var(--link, var(--rule)) 15%, var(--background));
}
}
@media (hover: none) {
.ph-link:hover {
background-color: transparent;
}
}
link.tsx
import type { AnchorHTMLAttributes, CSSProperties } from "react";
import { cn } from "./cn";
import "./link.css";
type LinkProps = AnchorHTMLAttributes<HTMLAnchorElement> & {
href: string;
tint?: string;
};
export function Link({ href, tint, className, style, ...rest }: LinkProps) {
const external = /^https?:\/\//.test(href);
return (
<a
href={href}
target={external ? "_blank" : undefined}
rel={external ? "noopener noreferrer" : undefined}
data-tint={tint ? "" : undefined}
className={cn("ph-link", className)}
style={tint ? ({ "--link": tint, ...style } as CSSProperties) : style}
{...rest}
/>
);
}
cn.ts
export const cn = (...parts: (string | false | null | undefined)[]) => parts.filter(Boolean).join(" ");