Compare commits

..

2 Commits

Author SHA1 Message Date
pluja
f4525e3d32 Release 2025-05-22-SwZ1 2025-05-22 23:07:55 +00:00
pluja
ecc8f67fc4 Release 2025-05-22-XDxe 2025-05-22 22:58:18 +00:00
3 changed files with 95 additions and 33 deletions

View File

@@ -27,7 +27,7 @@ export type ButtonProps<Tag extends 'a' | 'button' | 'label' = 'button'> = Props
const button = tv({ const button = tv({
slots: { slots: {
base: 'inline-flex items-center justify-center gap-2 rounded-lg border transition-colors duration-100 focus-visible:ring-2 focus-visible:ring-current focus-visible:ring-offset-2 focus-visible:ring-offset-black focus-visible:outline-hidden', base: 'inline-flex shrink-0 items-center justify-center gap-2 rounded-lg border transition-colors duration-100 focus-visible:ring-2 focus-visible:ring-current focus-visible:ring-offset-2 focus-visible:ring-offset-black focus-visible:outline-hidden',
icon: 'size-4 shrink-0', icon: 'size-4 shrink-0',
label: 'text-left whitespace-nowrap', label: 'text-left whitespace-nowrap',
endIcon: 'size-4 shrink-0', endIcon: 'size-4 shrink-0',
@@ -52,6 +52,11 @@ const button = tv({
label: 'font-bold tracking-wider uppercase', label: 'font-bold tracking-wider uppercase',
}, },
}, },
iconOnly: {
true: {
base: 'p-0',
},
},
color: { color: {
black: { black: {
base: 'border-night-500 bg-night-800 hover:bg-night-900 hover:text-day-200 focus-visible:bg-night-500 text-white/50 focus-visible:text-white focus-visible:ring-white', base: 'border-night-500 bg-night-800 hover:bg-night-900 hover:text-day-200 focus-visible:bg-night-500 text-white/50 focus-visible:text-white focus-visible:ring-white',
@@ -122,12 +127,28 @@ const button = tv({
shadow: true, shadow: true,
class: 'shadow-blue-500/30', class: 'shadow-blue-500/30',
}, },
{
iconOnly: true,
size: 'sm',
class: 'w-8',
},
{
iconOnly: true,
size: 'md',
class: 'w-9',
},
{
iconOnly: true,
size: 'lg',
class: 'w-10',
},
], ],
defaultVariants: { defaultVariants: {
size: 'md', size: 'md',
color: 'black', color: 'black',
shadow: false, shadow: false,
disabled: false, disabled: false,
iconOnly: false,
}, },
}) })
@@ -153,7 +174,7 @@ const {
icon: iconSlot, icon: iconSlot,
label: labelSlot, label: labelSlot,
endIcon: endIconSlot, endIcon: endIconSlot,
} = button({ size, color, shadow, disabled }) } = button({ size, color, shadow, disabled, iconOnly: !label && !(!!icon && !!endIcon) })
const ActualTag = disabled && Tag === 'a' ? 'span' : Tag const ActualTag = disabled && Tag === 'a' ? 'span' : Tag
--- ---

View File

@@ -22,7 +22,7 @@ type Props = HTMLAttributes<'div'> & {
sortSeed?: string sortSeed?: string
filters: ServicesFiltersObject filters: ServicesFiltersObject
includeScams: boolean includeScams: boolean
countIfIncludingCommunity: number | null countCommunityOnly: number | null
inlineIcons?: boolean inlineIcons?: boolean
} }
@@ -36,7 +36,7 @@ const {
class: className, class: className,
filters, filters,
includeScams, includeScams,
countIfIncludingCommunity, countCommunityOnly,
inlineIcons, inlineIcons,
...divProps ...divProps
} = Astro.props } = Astro.props
@@ -59,37 +59,67 @@ const urlIfIncludingCommunity = urlWithParams(Astro.url, {
verificationStatusesByValue.COMMUNITY_CONTRIBUTED.slug, verificationStatusesByValue.COMMUNITY_CONTRIBUTED.slug,
]), ]),
}) })
const extraIfIncludingCommunity = Math.max(0, (countIfIncludingCommunity ?? 0) - (services?.length ?? 0))
--- ---
<div {...divProps} class={cn('flex-1', className)}> <div {...divProps} class={cn('flex-1', className)}>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<span class="text-day-500 text-sm"> <span class="text-day-500 xs:gap-x-3 flex flex-wrap items-center gap-x-2 gap-y-1 text-sm sm:gap-x-6">
{total.toLocaleString()} {total.toLocaleString()}
{pluralize('result', total)} {pluralize('result', total)}
<Icon
name="ri:loader-4-line"
id="search-indicator"
class="htmx-request:opacity-100 xs:-mx-1.5 -mx-1 inline-block size-4 animate-spin text-white opacity-0 transition-opacity duration-500 sm:-mx-3"
is:inline={inlineIcons}
/>
{ {
extraIfIncludingCommunity > 0 && ( countCommunityOnly && (
<Button <>
as="a" <Button
href={urlIfIncludingCommunity} as="a"
label={`Include +${extraIfIncludingCommunity.toLocaleString()} community contributed`} href={urlIfIncludingCommunity}
size="sm" label={`Include +${countCommunityOnly.toLocaleString()} community contributed`}
class="ml-6 align-[-0.15em]" size="sm"
icon="ri:search-line" class="hidden lg:inline-flex"
inlineIcon={inlineIcons} icon="ri:search-line"
/> inlineIcon={inlineIcons}
/>
<Button
as="a"
href={urlIfIncludingCommunity}
label={`Include +${countCommunityOnly.toLocaleString()}`}
size="sm"
class="hidden sm:inline-flex lg:hidden"
icon="ri:search-line"
endIcon="ri:question-line"
classNames={{
endIcon: 'text-yellow-200/50',
}}
inlineIcon={inlineIcons}
/>
<a
href={urlIfIncludingCommunity}
class="border-night-500 bg-night-800 flex items-center gap-1 rounded-md border px-2 py-0.5 text-sm sm:hidden"
>
<Icon
name="ri:search-line"
class="mr-0.5 inline-block size-3.5 shrink-0 align-[-0.15em]"
is:inline={inlineIcons}
/>
Include
{countCommunityOnly.toLocaleString()}
<Icon
name="ri:question-line"
class="inline-block size-3.5 shrink-0 align-[-0.15em] text-yellow-200/50"
is:inline={inlineIcons}
/>
</a>
</>
) )
} }
<span
id="search-indicator"
class="htmx-request:opacity-100 text-white opacity-0 transition-opacity duration-500"
>
<Icon name="ri:loader-4-line" class="inline-block size-4 animate-spin" is:inline={inlineIcons} />
Loading...
</span>
</span> </span>
<Button <Button
as="a" as="a"
@@ -97,6 +127,10 @@ const extraIfIncludingCommunity = Math.max(0, (countIfIncludingCommunity ?? 0) -
label="Add service" label="Add service"
icon="ri:add-line" icon="ri:add-line"
inlineIcon={inlineIcons} inlineIcon={inlineIcons}
class="max-xs:w-9 max-xs:px-0"
classNames={{
label: 'max-xs:hidden',
}}
/> />
</div> </div>
@@ -162,11 +196,11 @@ const extraIfIncludingCommunity = Math.max(0, (countIfIncludingCommunity ?? 0) -
inlineIcon={inlineIcons} inlineIcon={inlineIcons}
/> />
)} )}
{extraIfIncludingCommunity > 0 && ( {countCommunityOnly && (
<Button <Button
as="a" as="a"
href={urlIfIncludingCommunity} href={urlIfIncludingCommunity}
label={`Show ${extraIfIncludingCommunity.toLocaleString()} community contributed`} label={`Show ${countCommunityOnly.toLocaleString()} community contributed`}
icon="ri:search-line" icon="ri:search-line"
inlineIcon={inlineIcons} inlineIcon={inlineIcons}
/> />
@@ -207,4 +241,14 @@ const extraIfIncludingCommunity = Math.max(0, (countIfIncludingCommunity ?? 0) -
</> </>
) )
} }
<div class="mt-4 text-center">
<Button
as="a"
href="/service-suggestion/new"
label="Add service"
icon="ri:add-line"
inlineIcon={inlineIcons}
class="mx-auto"
/>
</div>
</div> </div>

View File

@@ -310,7 +310,7 @@ const where = {
], ],
} as const satisfies Prisma.ServiceWhereInput } as const satisfies Prisma.ServiceWhereInput
const [categories, [services, totalServices], countIfIncludingCommunity, attributes] = const [categories, [services, totalServices], countCommunityOnly, attributes] =
await Astro.locals.banners.tryMany([ await Astro.locals.banners.tryMany([
[ [
'Unable to load category filters.', 'Unable to load category filters.',
@@ -416,10 +416,7 @@ const [categories, [services, totalServices], countIfIncludingCommunity, attribu
? prisma.service.count({ ? prisma.service.count({
where: { where: {
...where, ...where,
verificationStatus: { verificationStatus: 'COMMUNITY_CONTRIBUTED',
...where.verificationStatus,
in: uniq([...where.verificationStatus.in, 'COMMUNITY_CONTRIBUTED'] as const),
},
}, },
}) })
: null, : null,
@@ -707,7 +704,7 @@ const showFiltersId = 'show-filters'
sortSeed={filters['sort-seed']} sortSeed={filters['sort-seed']}
filters={filters} filters={filters}
includeScams={includeScams} includeScams={includeScams}
countIfIncludingCommunity={countIfIncludingCommunity} countCommunityOnly={countCommunityOnly}
inlineIcons inlineIcons
/> />
</div> </div>