This commit is contained in:
pluja
2025-05-19 21:31:29 +00:00
parent 636057f8e0
commit a21dc81099
13 changed files with 135 additions and 93 deletions

View File

@@ -203,7 +203,13 @@ const commentUrl = makeCommentUrl({ serviceSlug, commentId: comment.id, origin:
}
{
comment.author.verifier && !comment.author.admin && (
<BadgeSmall icon="ri:shield-check-fill" color="teal" text="Moderator" variant="faded" inlineIcon />
<BadgeSmall
icon="ri:graduation-cap-fill"
color="teal"
text="Moderator"
variant="faded"
inlineIcon
/>
)
}

View File

@@ -33,10 +33,10 @@ if (!user || !user.admin || !user.verifier) return null
---
<div {...divProps} class={cn('text-xs', className)}>
<input type="checkbox" id={`mod-toggle-${String(comment.id)}`} class="peer hidden" />
<input type="checkbox" id={`mod-toggle-${String(comment.id)}`} class="peer sr-only" />
<label
for={`mod-toggle-${String(comment.id)}`}
class="text-day-500 hover:text-day-300 flex cursor-pointer items-center gap-1"
class="text-day-500 hover:text-day-300 peer-focus-visible:ring-offset-night-700 inline-flex cursor-pointer items-center gap-1 rounded-sm peer-focus-visible:ring-2 peer-focus-visible:ring-blue-500 peer-focus-visible:ring-offset-2"
>
<Icon name="ri:shield-keyhole-line" class="h-3.5 w-3.5" />
<span class="text-xs">Moderation</span>
@@ -44,7 +44,7 @@ if (!user || !user.admin || !user.verifier) return null
</label>
<div
class="bg-night-600 border-night-500 mt-2 max-h-0 overflow-hidden rounded-md border opacity-0 transition-all duration-200 ease-in-out peer-checked:max-h-[500px] peer-checked:p-2 peer-checked:opacity-100"
class="bg-night-600 border-night-500 mt-2 hidden overflow-hidden rounded-md border peer-checked:block peer-checked:p-2"
>
<div class="border-night-500 flex flex-wrap gap-1 border-b pb-2">
<button

View File

@@ -20,6 +20,7 @@ type Props<Multiple extends boolean = false> = Omit<
iconClass?: string
description?: MarkdownString
disabled?: boolean
noTransitionPersist?: boolean
}[]
disabled?: boolean
selectedValue?: Multiple extends true ? string[] : string
@@ -39,13 +40,11 @@ const {
...wrapperProps
} = Astro.props
const inputId = Astro.locals.makeId(`input-${wrapperProps.name}`)
const hasError = !!wrapperProps.error && wrapperProps.error.length > 0
---
{/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */}
<InputWrapper inputId={inputId} class={cn('@container', className)} {...wrapperProps}>
<InputWrapper class={cn('@container', className)} {...wrapperProps}>
<div
class={cn(
'grid grid-cols-[repeat(auto-fill,minmax(var(--card-min-size),1fr))] gap-2 rounded-lg',
@@ -71,7 +70,7 @@ const hasError = !!wrapperProps.error && wrapperProps.error.length > 0
)}
>
<input
transition:persist
transition:persist={option.noTransitionPersist ? undefined : true}
type={multiple ? 'checkbox' : 'radio'}
name={wrapperProps.name}
value={option.value}

View File

@@ -42,7 +42,7 @@ const inputId = id ?? Astro.locals.makeId(`input-${wrapperProps.name}`)
{
ratings.toSorted().map((rating) => (
<label class="relative cursor-pointer [&:has(~_*:hover),&:hover]:[&>[data-star]]:opacity-100!">
<label class="relative cursor-pointer [&:has(~_*_*:checked)]:[&>[data-star]]:opacity-100 [&:has(~_*:hover),&:hover]:[&>[data-star]]:opacity-100!">
<input
type="radio"
name={wrapperProps.name}
@@ -54,7 +54,7 @@ const inputId = id ?? Astro.locals.makeId(`input-${wrapperProps.name}`)
<Icon name="ri:star-line" class="size-6 p-0.5 text-zinc-500" />
<Icon
name="ri:star-fill"
class="absolute top-0 left-0 size-6 p-0.5 text-yellow-400 not-peer-checked:opacity-0 group-hover/fieldset:opacity-0"
class="absolute top-0 left-0 size-6 p-0.5 text-yellow-400 not-peer-checked:opacity-0 group-hover/fieldset:opacity-0!"
data-star
/>
</label>

View File

@@ -17,7 +17,7 @@ const { name, options, selectedValue, class: className, ...rest } = Astro.props
<div
class={cn(
'bg-night-500 divide-night-700 flex divide-x-2 overflow-hidden rounded-md text-[0.6875rem]',
'bg-night-500 divide-night-700 has-focus-visible:ring-offset-night-700 flex divide-x-2 overflow-hidden rounded-md text-[0.6875rem] has-focus-visible:ring-2 has-focus-visible:ring-blue-500 has-focus-visible:ring-offset-2',
className
)}
{...rest}
@@ -30,7 +30,7 @@ const { name, options, selectedValue, class: className, ...rest } = Astro.props
name={name}
value={option.value}
checked={selectedValue === option.value}
class="peer hidden"
class="peer sr-only"
/>
<span class="peer-checked:bg-night-400 inline-block cursor-pointer px-1.5 py-0.5 text-white peer-checked:text-green-500">
{option.label}

View File

@@ -112,7 +112,7 @@ if (!z.string().url().safeParse(link.url).success) {
target="_blank"
rel="noopener noreferrer"
class={cn(
'2xs:text-sm 2xs:h-8 2xs:gap-2 inline-flex h-6 items-center gap-1 rounded-full bg-white text-xs whitespace-nowrap text-black',
'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}

View File

@@ -97,8 +97,7 @@ const {
<!-- Type Filter -->
<fieldset class="mb-6">
<legend class="font-title mb-3 leading-none text-green-500">Type</legend>
<input type="checkbox" id="show-more-categories" class="peer hidden" hx-preserve data-show-more-input />
<ul class="not-peer-checked:[&>li:not([data-show-always])]:hidden">
<ul class="[&:not(:has(~_.peer:checked))]:[&>li:not([data-show-always])]:hidden">
{
options.categories?.map((category) => (
<li data-show-always={category.showAlways ? '' : undefined}>
@@ -122,15 +121,22 @@ const {
{
options.categories.filter((category) => category.showAlways).length < options.categories.length && (
<>
<input
type="checkbox"
id="show-more-categories"
class="peer sr-only"
hx-preserve
data-show-more-input
/>
<label
for="show-more-categories"
class="mt-2 block cursor-pointer text-sm text-green-500 peer-checked:hidden"
class="peer-focus-visible:ring-offset-night-700 mt-2 block cursor-pointer rounded-sm text-sm text-green-500 peer-checked:hidden peer-focus-visible:ring-2 peer-focus-visible:ring-blue-500 peer-focus-visible:ring-offset-2"
>
+ Show more
</label>
<label
for="show-more-categories"
class="mt-2 hidden cursor-pointer text-sm text-green-500 peer-checked:block"
class="peer-focus-visible:ring-offset-night-700 mt-2 hidden cursor-pointer rounded-sm text-sm text-green-500 peer-checked:block peer-focus-visible:ring-2 peer-focus-visible:ring-blue-500 peer-focus-visible:ring-offset-2"
>
- Show less
</label>
@@ -289,14 +295,8 @@ const {
options.attributesByCategory.map(({ category, attributes }) => (
<fieldset class="min-w-0">
<legend class="font-title mb-0.5 text-xs tracking-wide text-white">{category}</legend>
<input
type="checkbox"
id={`show-more-attributes-${category}`}
class="peer hidden"
hx-preserve
data-show-more-input
/>
<ul class="not-peer-checked:[&>li:not([data-show-always])]:hidden">
<ul class="[:not(:has(~_.peer:checked))]:[&>li:not([data-show-always])]:hidden">
{attributes.map((attribute) => {
const inputName = `attr-${attribute.id}` as const
const yesId = `attr-${attribute.id}=yes` as const
@@ -306,13 +306,13 @@ const {
return (
<li data-show-always={attribute.showAlways ? '' : undefined} class="cursor-pointer">
<fieldset class="flex max-w-full min-w-0 cursor-pointer items-center text-sm text-white">
<fieldset class="relative flex max-w-full min-w-0 cursor-pointer items-center text-sm text-white">
<legend class="sr-only">
{attribute.title} ({attribute._count?.services})
</legend>
<input
type="radio"
class="peer/empty hidden"
class="peer/empty sr-only"
id={emptyId}
name={inputName}
value=""
@@ -324,7 +324,7 @@ const {
name={inputName}
value="yes"
id={yesId}
class="peer/yes hidden"
class="peer/yes sr-only"
checked={attribute.value === 'yes'}
aria-label="Include"
/>
@@ -333,38 +333,45 @@ const {
name={inputName}
value="no"
id={noId}
class="peer/no hidden"
class="peer/no sr-only"
checked={attribute.value === 'no'}
aria-label="Exclude"
/>
<div class="pointer-events-none absolute inset-y-0 -left-[2px] hidden w-[calc(var(--spacing)*4.5*2+1px)] rounded-md border-2 border-blue-500 peer-focus-visible/empty:block peer-focus-visible/no:block peer-focus-visible/yes:block" />
<label
for={yesId}
class="flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-l-sm bg-zinc-950 peer-checked/yes:hidden"
class="border-night-500 bg-night-600 relative flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-l-sm border border-r-0 peer-checked/yes:hidden before:absolute before:-inset-[3px] before:-right-[0.5px]"
aria-hidden="true"
>
<Icon name="ri:check-line" class="size-3" />
</label>
<label
for={emptyId}
class="hidden size-4 shrink-0 cursor-pointer items-center justify-center rounded-l-sm bg-green-600 peer-checked/yes:flex"
class="relative hidden h-4 w-[calc(var(--spacing)*4+0.5px)] shrink-0 cursor-pointer items-center justify-center rounded-l-sm bg-green-600 peer-checked/yes:flex before:absolute before:-inset-[2px] before:-right-[0.5px]"
aria-hidden="true"
>
<Icon name="ri:check-line" class="size-3" />
</label>
<span class="block h-4 w-px border-y-2 border-zinc-950 bg-zinc-800" aria-hidden="true" />
<span
class="bg-night-400 border-night-500 pointer-events-none block h-4 w-px border-y peer-checked/no:w-[0.5px] peer-checked/yes:w-[0.5px]"
aria-hidden="true"
>
<span class="bg-night-400 border-night-600 block h-full w-px border-y-2" />
</span>
<label
for={noId}
class="flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-r-sm bg-zinc-950 peer-checked/no:hidden"
class="border-night-500 bg-night-600 relative flex size-4 shrink-0 cursor-pointer items-center justify-center rounded-r-sm border border-l-0 peer-checked/no:hidden before:absolute before:-inset-[3px] before:-left-[0.5px]"
aria-hidden="true"
>
<Icon name="ri:close-line" class="size-3" />
</label>
<label
for={emptyId}
class="hidden size-4 shrink-0 cursor-pointer items-center justify-center rounded-r-sm bg-red-600 peer-checked/no:flex"
class="relative hidden size-4 w-[calc(var(--spacing)*4+0.5px)] shrink-0 cursor-pointer items-center justify-center rounded-r-sm bg-red-600 peer-checked/no:flex before:absolute before:-inset-[2px] before:-left-[0.5px]"
aria-hidden="true"
>
<Icon name="ri:close-line" class="size-3" />
@@ -376,8 +383,8 @@ const {
aria-hidden="true"
>
<Icon
name={attribute.icon}
class={cn('mr-2 size-3 shrink-0 opacity-80', attribute.iconClass)}
name={attribute.info.icon}
class={cn('mr-2 size-3 shrink-0 opacity-80', attribute.info.classNames.icon)}
aria-hidden="true"
/>
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">
@@ -391,8 +398,8 @@ const {
aria-hidden="true"
>
<Icon
name={attribute.icon}
class={cn('mr-2 size-3 shrink-0 opacity-100', attribute.iconClass)}
name={attribute.info.icon}
class={cn('mr-2 size-3 shrink-0 opacity-100', attribute.info.classNames.icon)}
aria-hidden="true"
/>
<span class="flex-1 overflow-hidden text-ellipsis whitespace-nowrap">
@@ -405,17 +412,25 @@ const {
)
})}
</ul>
{attributes.filter((attribute) => attribute.showAlways).length < attributes.length && (
<>
<input
type="checkbox"
id={`show-more-attributes-${category}`}
class="peer sr-only"
hx-preserve
data-show-more-input
/>
<label
for={`show-more-attributes-${category}`}
class="mt-2 block cursor-pointer text-sm text-green-500 peer-checked:hidden"
class="peer-focus-visible:ring-offset-night-700 mt-2 block cursor-pointer rounded-sm text-sm text-green-500 peer-checked:hidden peer-focus-visible:ring-2 peer-focus-visible:ring-blue-500 peer-focus-visible:ring-offset-2"
>
+ Show more
</label>
<label
for={`show-more-attributes-${category}`}
class="mt-2 hidden cursor-pointer text-sm text-green-500 peer-checked:block"
class="peer-focus-visible:ring-offset-night-700 mt-2 hidden cursor-pointer rounded-sm text-sm text-green-500 peer-checked:block peer-focus-visible:ring-2 peer-focus-visible:ring-blue-500 peer-focus-visible:ring-offset-2"
>
- Show less
</label>