Compare commits

...

2 Commits

Author SHA1 Message Date
pluja
85605de8aa Release 2025-05-23-S6tT 2025-05-23 14:56:00 +00:00
pluja
7a22629c55 Release 2025-05-23-JSHi 2025-05-23 12:25:07 +00:00
3 changed files with 24 additions and 27 deletions

View File

@@ -18,7 +18,7 @@ const serviceSchemaBase = z.object({
slug: z
.string()
.regex(/^[a-z0-9-]+$/, 'Allowed characters: lowercase letters, numbers, and hyphens')
.nullable(),
.optional(),
name: z.string().min(1).max(20),
description: z.string().min(1),
serviceUrls: stringListOfUrlsSchemaRequired,
@@ -28,12 +28,12 @@ const serviceSchemaBase = z.object({
attributes: z.array(z.coerce.number().int().positive()),
categories: z.array(z.coerce.number().int().positive()).min(1),
verificationStatus: z.nativeEnum(VerificationStatus),
verificationSummary: z.string().nullable(),
verificationProofMd: z.string().nullable(),
verificationSummary: z.string().optional().nullable().default(null),
verificationProofMd: z.string().optional().nullable().default(null),
acceptedCurrencies: z.array(z.nativeEnum(Currency)),
referral: z.string().nullable(),
referral: z.string().optional().nullable().default(null),
imageFile: imageFileSchema,
overallScore: zodCohercedNumber(z.number().int().min(0).max(10)).nullable(),
overallScore: zodCohercedNumber(z.number().int().min(0).max(10)).optional(),
serviceVisibility: z.nativeEnum(ServiceVisibility),
})

View File

@@ -30,14 +30,14 @@ export const {
{
type: 'email',
label: 'Email',
matcher: /mailto:(.*)/,
matcher: /mailto:(.+)/,
formatter: (value) => value,
icon: 'ri:mail-line',
},
{
type: 'telephone',
label: 'Telephone',
matcher: /tel:(.*)/,
matcher: /tel:(.+)/,
formatter: (value) => {
return parsePhoneNumberWithError(value).formatInternational()
},
@@ -46,7 +46,7 @@ export const {
{
type: 'whatsapp',
label: 'WhatsApp',
matcher: /https?:\/\/(?:www\.)?wa\.me\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?wa\.me\/(.+)/,
formatter: (value) => {
return parsePhoneNumberWithError(value).formatInternational()
},
@@ -55,42 +55,35 @@ export const {
{
type: 'telegram',
label: 'Telegram',
matcher: /https?:\/\/(?:www\.)?t\.me\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?t\.me\/(.+)/,
formatter: (value) => `t.me/${value}`,
icon: 'ri:telegram-line',
},
{
type: 'linkedin',
label: 'LinkedIn',
matcher: /https?:\/\/(?:www\.)?linkedin\.com\/(?:in|company)\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?linkedin\.com\/(?:in|company)\/(.+)/,
formatter: (value) => `in/${value}`,
icon: 'ri:linkedin-box-line',
},
{
type: 'website',
label: 'Website',
matcher: /https?:\/\/(?:www\.)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]+)/,
formatter: (value) => value,
icon: 'ri:global-line',
},
{
type: 'x',
label: 'X',
matcher: /https?:\/\/(?:www\.)?x\.com\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?x\.com\/(.+)/,
formatter: (value) => `@${value}`,
icon: 'ri:twitter-x-line',
},
{
type: 'instagram',
label: 'Instagram',
matcher: /https?:\/\/(?:www\.)?instagram\.com\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?instagram\.com\/(.+)/,
formatter: (value) => `@${value}`,
icon: 'ri:instagram-line',
},
{
type: 'matrix',
label: 'Matrix',
matcher: /https?:\/\/(?:www\.)?matrix\.to\/#\/(.*)?/,
matcher: /https?:\/\/(?:www\.)?matrix\.to\/#\/(.+)/,
formatter: (value) => value,
icon: 'ri:hashtag',
},
@@ -101,6 +94,14 @@ export const {
formatter: () => 'BitcoinTalk',
icon: 'ri:btc-line',
},
// 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,
icon: 'ri:global-line',
},
] as const satisfies ContactMethodInfo[]
)

View File

@@ -170,8 +170,6 @@ const errorTextClasses = 'mt-1 text-xs text-red-400'
</h1>
<a
href={`/service/${service.slug}`}
target="_blank"
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-sm text-sky-400 hover:text-sky-300 hover:underline focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 focus:ring-offset-zinc-900 focus:outline-none"
>
<Icon name="ri:external-link-line" class="size-4" />
@@ -1017,12 +1015,10 @@ const errorTextClasses = 'mt-1 text-xs text-red-400'
<div class="flex-grow space-y-1">
<div class="flex flex-wrap items-center gap-2">
<Icon name={contactMethodInfo.icon} class="size-4 text-zinc-300" />
<span class="text-md font-semibold text-zinc-100">
{method.label ?? contactMethodInfo.label}
</span>
<span class="text-md font-semibold text-zinc-100">{contactMethodInfo.label}</span>
</div>
<p class="text-sm text-pretty text-zinc-400">
{contactMethodInfo.formattedValue}{' '}
{method.label ?? contactMethodInfo.formattedValue}{' '}
<span class="text-zinc-500">({method.value})</span>
</p>
</div>
@@ -1067,7 +1063,7 @@ const errorTextClasses = 'mt-1 text-xs text-red-400'
id={`contactLabel-${method.id}`}
value={method.label}
class={inputBaseClasses}
placeholder={contactMethodInfo.label}
placeholder={contactMethodInfo.formattedValue}
/>
</div>
<div>