152 lines
3.9 KiB
Plaintext
152 lines
3.9 KiB
Plaintext
---
|
|
import { z } from 'astro/zod'
|
|
import { Icon } from 'astro-icon/components'
|
|
|
|
import { networksBySlug } from '../constants/networks'
|
|
import { cn } from '../lib/cn'
|
|
|
|
import type { HTMLAttributes } from 'astro/types'
|
|
|
|
type Props = Omit<HTMLAttributes<'a'>, 'href' | 'rel' | 'target'> & {
|
|
url: string
|
|
referral: string | null
|
|
enableMinWidth?: boolean
|
|
}
|
|
|
|
const { url: baseUrl, referral, class: className, enableMinWidth = false, ...htmlProps } = Astro.props
|
|
|
|
function makeLink(url: string, referral: string | null) {
|
|
const hostname = new URL(url).hostname
|
|
const urlWithReferral = url + (referral ?? '')
|
|
|
|
const onionMatch = /^(?:https?:\/\/)?(.{0,10}).*?(.{0,10})(\.onion)$/.exec(hostname)
|
|
if (onionMatch) {
|
|
return {
|
|
type: 'onion' as const,
|
|
url: urlWithReferral,
|
|
textBits: onionMatch.length
|
|
? [
|
|
{
|
|
style: 'normal' as const,
|
|
text: onionMatch[1] ?? '',
|
|
},
|
|
{
|
|
style: 'irrelevant' as const,
|
|
text: '...',
|
|
},
|
|
{
|
|
style: 'normal' as const,
|
|
text: onionMatch[2] ?? '',
|
|
},
|
|
{
|
|
style: 'irrelevant' as const,
|
|
text: onionMatch[3] ?? '',
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
style: 'normal' as const,
|
|
text: hostname,
|
|
},
|
|
],
|
|
icon: networksBySlug.onion.icon,
|
|
}
|
|
}
|
|
|
|
const i2pMatch = /^(?:https?:\/\/)?(.{0,10}).*?(.{0,8})((?:\.b32)?\.i2p)$/.exec(hostname)
|
|
if (i2pMatch) {
|
|
return {
|
|
type: 'i2p' as const,
|
|
url: urlWithReferral,
|
|
textBits: i2pMatch.length
|
|
? [
|
|
{
|
|
style: 'normal' as const,
|
|
text: i2pMatch[1] ?? '',
|
|
},
|
|
{
|
|
style: 'irrelevant' as const,
|
|
text: '...',
|
|
},
|
|
{
|
|
style: 'normal' as const,
|
|
text: i2pMatch[2] ?? '',
|
|
},
|
|
{
|
|
style: 'irrelevant' as const,
|
|
text: i2pMatch[3] ?? '',
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
style: 'normal' as const,
|
|
text: hostname,
|
|
},
|
|
],
|
|
icon: networksBySlug.i2p.icon,
|
|
}
|
|
}
|
|
|
|
const bitcointalkMatch = /^(?:https?:\/\/)?(?:www\.)?bitcointalk\.org$/.exec(hostname)
|
|
if (bitcointalkMatch) {
|
|
return {
|
|
type: 'clearnet' as const,
|
|
url: urlWithReferral,
|
|
textBits: [
|
|
{
|
|
style: 'normal',
|
|
text: 'BitcoinTalk ',
|
|
},
|
|
{
|
|
style: 'irrelevant',
|
|
text: 'thread',
|
|
},
|
|
],
|
|
icon: networksBySlug.clearnet.icon,
|
|
}
|
|
}
|
|
|
|
return {
|
|
type: 'clearnet' as const,
|
|
url: urlWithReferral,
|
|
textBits: [
|
|
{
|
|
style: 'normal' as const,
|
|
text: hostname.replace(/^www\./, ''),
|
|
},
|
|
],
|
|
icon: networksBySlug.clearnet.icon,
|
|
}
|
|
}
|
|
|
|
const link = makeLink(baseUrl, referral)
|
|
|
|
if (!z.string().url().safeParse(link.url).success) {
|
|
console.error(`Invalid service URL with referral: ${link.url}`)
|
|
}
|
|
---
|
|
|
|
<a
|
|
href={link.url}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class={cn(
|
|
'2xs:text-sm 2xs:h-8 2xs:gap-2 focus-visible:ring-offset-night-700 inline-flex h-6 items-center gap-1 rounded-full bg-white text-xs whitespace-nowrap text-black focus-visible:ring-4 focus-visible:ring-orange-500 focus-visible:ring-offset-2 focus-visible:outline-none',
|
|
className
|
|
)}
|
|
{...htmlProps}
|
|
>
|
|
<Icon name={link.icon} class="2xs:ml-2 2xs:size-5 2xs:-mr-0.5 -mr-0.25 ml-1 size-4" />
|
|
<span class={cn('font-title font-bold', { 'min-w-[29ch]': enableMinWidth })}>
|
|
{
|
|
link.textBits.map((textBit) => (
|
|
<span class={cn(textBit.style === 'irrelevant' && 'text-zinc-500')}>{textBit.text}</span>
|
|
))
|
|
}
|
|
</span>
|
|
<Icon
|
|
name="ri:arrow-right-line"
|
|
class="2xs:size-6 mr-1 size-4 rounded-full bg-orange-500 p-0.5 text-white"
|
|
/>
|
|
</a>
|