Files

123 lines
3.5 KiB
TypeScript

import { useFrontmatter } from "@rspress/core/runtime"
// MD5 — self-contained, works in any JS environment
function md5Hex(message: string): string {
const S = [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
]
const T: number[] = []
for (let i = 0; i < 64; i++) {
T[i] = Math.floor(Math.abs(Math.sin(i + 1)) * 0x100000000) | 0
}
const bytes: number[] = []
for (let i = 0; i < message.length; i++) {
const c = message.charCodeAt(i)
if (c < 0x80) bytes.push(c)
else if (c < 0x800) {
bytes.push(0xc0 | (c >> 6))
bytes.push(0x80 | (c & 0x3f))
} else {
bytes.push(0xe0 | (c >> 12))
bytes.push(0x80 | ((c >> 6) & 0x3f))
bytes.push(0x80 | (c & 0x3f))
}
}
const bitLen = bytes.length * 8
bytes.push(0x80)
while ((bytes.length + 8) % 64 !== 0) bytes.push(0)
for (let i = 0; i < 4; i++) bytes.push((bitLen >>> (i * 8)) & 0xff)
for (let i = 0; i < 4; i++) bytes.push(0)
let a0 = 0x67452301,
b0 = 0xefcdab89,
c0 = 0x98badcfe,
d0 = 0x10325476
for (let offset = 0; offset < bytes.length; offset += 64) {
const M = new Array(16)
for (let i = 0; i < 16; i++) {
M[i] =
bytes[offset + i * 4] |
(bytes[offset + i * 4 + 1] << 8) |
(bytes[offset + i * 4 + 2] << 16) |
(bytes[offset + i * 4 + 3] << 24)
}
let A = a0,
B = b0,
C = c0,
D = d0
for (let i = 0; i < 64; i++) {
let F: number, g: number
if (i < 16) {
F = (B & C) | (~B & D)
g = i
} else if (i < 32) {
F = (D & B) | (~D & C)
g = (5 * i + 1) % 16
} else if (i < 48) {
F = B ^ C ^ D
g = (3 * i + 5) % 16
} else {
F = C ^ (B | ~D)
g = (7 * i) % 16
}
F = (F + A + T[i] + M[g]) | 0
A = D
D = C
C = B
B = (B + ((F << S[i]) | (F >>> (32 - S[i])))) | 0
}
a0 = (a0 + A) | 0
b0 = (b0 + B) | 0
c0 = (c0 + C) | 0
d0 = (d0 + D) | 0
}
return [a0, b0, c0, d0]
.map(
(x) =>
((x >>> 0) & 0xff).toString(16).padStart(2, "0") +
((x >>> 8) & 0xff).toString(16).padStart(2, "0") +
((x >>> 16) & 0xff).toString(16).padStart(2, "0") +
((x >>> 24) & 0xff).toString(16).padStart(2, "0")
)
.join("")
}
function gravatarUrl(email: string, size = 80): string {
const normalized = email.trim().toLowerCase()
const hash = md5Hex(normalized)
return `https://cravatar.cn/avatar/${hash}?s=${size}&d=robohash&r=g`
}
interface AuthorInfo {
name?: string
email?: string
}
export function Author({ className }: { className?: string }) {
const { frontmatter } = useFrontmatter()
const author = frontmatter?.author as AuthorInfo | undefined
if (!author?.name?.trim()) return null
const src = author.email?.trim() ? gravatarUrl(author.email) : null
return (
<a
href={author.email?.trim() ? `mailto:${author.email}` : undefined}
className={`flex items-center gap-2 my-6 p-1 rounded-full border border-(--rp-c-divider) bg-(--rp-c-bg-soft) no-underline transition-colors hover:bg-(--rp-c-bg-mute) cursor-pointer select-none w-fit ${className ? `${className}` : ""}`}>
{src && <img src={src} alt={author.name} width={32} height={32} className="rounded-full" />}
<span className="text-sm text-(--rp-c-text-2) pr-2">{author.name}</span>
</a>
)
}