style(web): keep market tag filter on a single horizontal-scroll row

With many category tags the quick-filter row used `sm:flex-wrap` on
desktop, so once tags overflowed the available width they wrapped onto a
second, center-aligned line — leaving an orphan tag floating under the
row (looked broken and only gets worse as more tags are added).

Make the row a single, never-wrapping line that scrolls horizontally at
every breakpoint, left-aligned, with the scrollbar hidden and a subtle
right-edge fade to signal there's more to scroll. Adds a reusable
`.scrollbar-hide` utility to global.css.
This commit is contained in:
RockChinQ
2026-06-19 06:15:31 -04:00
parent 3d5b70cc5d
commit 65fbf4db59
2 changed files with 45 additions and 32 deletions
+9
View File
@@ -74,6 +74,15 @@
} }
} }
/* Hide scrollbar while keeping scroll behaviour (horizontal tag/filter rows). */
.scrollbar-hide {
-ms-overflow-style: none; /* IE / Edge */
scrollbar-width: none; /* Firefox */
}
.scrollbar-hide::-webkit-scrollbar {
display: none; /* Chrome / Safari / WebKit */
}
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@theme inline { @theme inline {
@@ -787,38 +787,42 @@ function MarketPageContent({
</div> </div>
</div> </div>
{/* 用真实标签做快速筛选 */} {/* 用真实标签做快速筛选 —— 始终单行横向滚动,避免标签变多时换行错位 */}
<div className="mx-auto flex w-full max-w-4xl items-center gap-2 overflow-x-auto pb-1 sm:flex-wrap sm:justify-center sm:overflow-visible"> <div className="relative mx-auto w-full max-w-4xl">
<Button <div className="scrollbar-hide flex items-center gap-2 overflow-x-auto pb-1 pr-6">
type="button" <Button
variant={selectedTags.length === 0 ? 'secondary' : 'ghost'} type="button"
size="sm" variant={selectedTags.length === 0 ? 'secondary' : 'ghost'}
className="h-8 shrink-0" size="sm"
onClick={() => handleTagsChange([])} className="h-8 shrink-0"
> onClick={() => handleTagsChange([])}
{t('market.allExtensions')} >
</Button> {t('market.allExtensions')}
{availableTags.map((tag) => { </Button>
const selected = selectedTags.includes(tag.tag); {availableTags.map((tag) => {
return ( const selected = selectedTags.includes(tag.tag);
<Button return (
key={tag.tag} <Button
type="button" key={tag.tag}
variant={selected ? 'secondary' : 'ghost'} type="button"
size="sm" variant={selected ? 'secondary' : 'ghost'}
className="h-8 shrink-0" size="sm"
onClick={() => { className="h-8 shrink-0"
const newTags = selected onClick={() => {
? selectedTags.filter((t) => t !== tag.tag) const newTags = selected
: [...selectedTags, tag.tag]; ? selectedTags.filter((t) => t !== tag.tag)
handleTagsChange(newTags); : [...selectedTags, tag.tag];
}} handleTagsChange(newTags);
> }}
{tagNames[tag.tag] || tag.tag} >
{selected && <X className="h-3.5 w-3.5" />} {tagNames[tag.tag] || tag.tag}
</Button> {selected && <X className="h-3.5 w-3.5" />}
); </Button>
})} );
})}
</div>
{/* 右侧渐隐,提示还有更多标签可横向滚动查看 */}
<div className="pointer-events-none absolute right-0 top-0 bottom-1 w-8 bg-gradient-to-l from-background to-transparent" />
</div> </div>
</div> </div>