Release 202505261604

This commit is contained in:
pluja
2025-05-26 16:04:25 +00:00
parent 50ede46d50
commit b361ed3aa8
4 changed files with 51 additions and 25 deletions

View File

@@ -160,6 +160,7 @@ const splashText = showSplashText ? sample(splashTexts) : null
<a
href={makeUnimpersonateUrl(Astro.url)}
data-astro-reload
data-astro-prefetch="tap"
class="xs:px-3 2xs:px-2 last:xs:-mr-3 last:2xs:-mr-2 flex h-full items-center px-1 text-sm text-stone-100 transition-colors last:-mr-1 hover:text-stone-200"
transition:name="header-unimpersonate-link"
aria-label="Unimpersonate"

View File

@@ -8,7 +8,7 @@ type ContactMethodInfo<T extends string | null | undefined = string> = {
label: string
/** Notice that the first capture group is then used to format the value */
matcher: RegExp
formatter: (value: string) => string | null
formatter: (match: RegExpMatchArray) => string | null
icon: string
}
@@ -24,82 +24,96 @@ export const {
label: type ? transformCase(type, 'title') : String(type),
icon: 'ri:shield-fill',
matcher: /(.*)/,
formatter: (value) => value,
formatter: ([, value]) => value ?? String(value),
}),
[
{
type: 'email',
label: 'Email',
matcher: /mailto:(.+)/,
formatter: (value) => value,
formatter: ([, value]) => value ?? 'Email',
icon: 'ri:mail-line',
},
{
type: 'telephone',
label: 'Telephone',
matcher: /tel:(.+)/,
formatter: (value) => {
return parsePhoneNumberWithError(value).formatInternational()
formatter: ([, value]) => {
return value ? parsePhoneNumberWithError(value).formatInternational() : 'Telephone'
},
icon: 'ri:phone-line',
},
{
type: 'whatsapp',
label: 'WhatsApp',
matcher: /https?:\/\/(?:www\.)?wa\.me\/(.+)/,
formatter: (value) => {
return parsePhoneNumberWithError(value).formatInternational()
matcher: /^https?:\/\/(?:www\.)?wa\.me\/(.+)/,
formatter: ([, value]) => {
return value ? parsePhoneNumberWithError(value).formatInternational() : 'WhatsApp'
},
icon: 'ri:whatsapp-line',
},
{
type: 'telegram',
label: 'Telegram',
matcher: /https?:\/\/(?:www\.)?t\.me\/(.+)/,
formatter: (value) => `t.me/${value}`,
matcher: /^https?:\/\/(?:www\.)?t\.me\/(.+)/,
formatter: ([, value]) => (value ? `t.me/${value}` : 'Telegram'),
icon: 'ri:telegram-line',
},
{
type: 'linkedin',
label: 'LinkedIn',
matcher: /https?:\/\/(?:www\.)?linkedin\.com\/(?:in|company)\/(.+)/,
formatter: (value) => `in/${value}`,
matcher: /^https?:\/\/(?:www\.)?linkedin\.com\/(?:in|company)\/(.+)/,
formatter: ([, value]) => (value ? `in/${value}` : 'LinkedIn'),
icon: 'ri:linkedin-box-line',
},
{
type: 'x',
label: 'X',
matcher: /https?:\/\/(?:www\.)?x\.com\/(.+)/,
formatter: (value) => `@${value}`,
matcher: /^https?:\/\/(?:www\.)?x\.com\/(.+)/,
formatter: ([, value]) => (value ? `@${value}` : 'X'),
icon: 'ri:twitter-x-line',
},
{
type: 'instagram',
label: 'Instagram',
matcher: /https?:\/\/(?:www\.)?instagram\.com\/(.+)/,
formatter: (value) => `@${value}`,
matcher: /^https?:\/\/(?:www\.)?instagram\.com\/(.+)/,
formatter: ([, value]) => (value ? `@${value}` : 'Instagram'),
icon: 'ri:instagram-line',
},
{
type: 'matrix',
label: 'Matrix',
matcher: /https?:\/\/(?:www\.)?matrix\.to\/#\/(.+)/,
formatter: (value) => value,
matcher: /^https?:\/\/(?:www\.)?matrix\.to\/#\/(.+)/,
formatter: ([, value]) => (value ? `#${value}` : 'Matrix'),
icon: 'ri:hashtag',
},
{
type: 'bitcointalk',
label: 'BitcoinTalk',
matcher: /https?:\/\/(?:www\.)?bitcointalk\.org/,
matcher: /^https?:\/\/(?:www\.)?bitcointalk\.org/,
formatter: () => 'BitcoinTalk',
icon: 'ri:btc-line',
},
// Website must go last because it's a catch-all
{
type: 'simplex',
label: 'SimpleX Chat',
matcher: /^https?:\/\/(?:www\.)?(simplex\.chat)\//,
formatter: () => 'SimpleX Chat',
icon: 'simplex',
},
{
type: 'nostr',
label: 'Nostr',
matcher: /\b(npub1[a-zA-Z0-9]{58})\b/,
formatter: () => 'Nostr',
icon: 'nostr',
},
{
// Website must go last because it's a catch-all
type: 'website',
label: 'Website',
matcher: /https?:\/\/(?:www\.)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]+)/,
formatter: (value) => value,
matcher: /^https?:\/\/(?:www\.)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]+)/,
formatter: ([, value]) => value ?? 'Website',
icon: 'ri:global-line',
},
] as const satisfies ContactMethodInfo[]
@@ -107,10 +121,10 @@ export const {
export function formatContactMethod(url: string) {
for (const contactMethod of contactMethods) {
const captureGroup = url.match(contactMethod.matcher)?.[1]
if (!captureGroup) continue
const match = url.match(contactMethod.matcher)
if (!match) continue
const formattedValue = contactMethod.formatter(captureGroup)
const formattedValue = contactMethod.formatter(match)
if (!formattedValue) continue
return {

View File

@@ -67,6 +67,15 @@ Once submitted, you get a unique tracking page where you can monitor its status
All new listings begin as **unlisted** — they're only accessible via direct link and won't appear in search results. After a brief admin review to confirm the request isn't spam or inappropriate, the listing will be marked as **Community Contributed**.
#### Requirements
To list a new service, it must fulfill these requirements:
- Publicly available website explaining what the service is about
- Terms of service or FAQ document
For example, just a Telegram link is not a valid service.
### Suggestion Review Process
#### First Review

View File

@@ -50,6 +50,7 @@ if (reasonType === 'admin-required' && Astro.locals.user?.admin) {
<a
href={makeLoginUrl(Astro.url, { redirect, logout: true, message: reason })}
data-astro-reload
data-astro-prefetch="tap"
class="focus-visible:outline-primary group flex items-center gap-2 px-3.5 py-2.5 text-white"
>
<Icon
@@ -62,6 +63,7 @@ if (reasonType === 'admin-required' && Astro.locals.user?.admin) {
Astro.locals.actualUser && (
<a
href={makeUnimpersonateUrl(Astro.url, { redirect })}
data-astro-prefetch="tap"
class="focus-visible:outline-primary group flex items-center gap-2 px-3.5 py-2.5 text-white"
>
<Icon