-
Notifications
You must be signed in to change notification settings - Fork 3
feat: separate official trending from custom tags #341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f6f54c3
0b6b129
0532812
32fbae6
68227fd
51158a0
ed05913
da37eae
e3c7523
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| 'use client'; | ||
|
|
||
| import type { IconType } from 'react-icons'; | ||
| import { AiOutlineThunderbolt, AiOutlineEye, AiOutlineRocket } from 'react-icons/ai'; | ||
| import { FaGem } from 'react-icons/fa'; | ||
| import { TbTrendingUp, TbTrendingDown } from 'react-icons/tb'; | ||
| import type { CustomTagIconId } from '@/stores/useMarketPreferences'; | ||
|
|
||
| /** | ||
| * Mapping of icon IDs to react-icons components. | ||
| * Keep this in sync with CUSTOM_TAG_ICONS in useMarketPreferences. | ||
| */ | ||
| export const ICON_MAP: Record<CustomTagIconId, IconType> = { | ||
| 'trend-up': TbTrendingUp, | ||
| 'trend-down': TbTrendingDown, | ||
| rocket: AiOutlineRocket, | ||
| gem: FaGem, | ||
| bolt: AiOutlineThunderbolt, | ||
| eye: AiOutlineEye, | ||
| }; | ||
|
|
||
| type CustomTagIconProps = { | ||
| iconId: CustomTagIconId; | ||
| size?: number; | ||
| className?: string; | ||
| }; | ||
|
|
||
| /** | ||
| * Render a custom tag icon by its ID. | ||
| */ | ||
| export function CustomTagIcon({ iconId, size = 14, className = '' }: CustomTagIconProps) { | ||
| const IconComponent = ICON_MAP[iconId]; | ||
| if (!IconComponent) return null; | ||
| return ( | ||
| <IconComponent | ||
| size={size} | ||
| className={className} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Icon picker component for selecting custom tag icons. | ||
| */ | ||
| type IconPickerProps = { | ||
| selectedIcon: CustomTagIconId; | ||
| onSelect: (icon: CustomTagIconId) => void; | ||
| disabled?: boolean; | ||
| }; | ||
|
|
||
| export function CustomTagIconPicker({ selectedIcon, onSelect, disabled = false }: IconPickerProps) { | ||
| return ( | ||
| <div className="flex flex-wrap gap-1.5"> | ||
| {(Object.keys(ICON_MAP) as CustomTagIconId[]).map((iconId) => { | ||
| const IconComponent = ICON_MAP[iconId]; | ||
| const isSelected = iconId === selectedIcon; | ||
|
|
||
| return ( | ||
| <button | ||
| key={iconId} | ||
| type="button" | ||
| onClick={() => onSelect(iconId)} | ||
| disabled={disabled} | ||
| aria-pressed={isSelected} | ||
| aria-label={`Select ${iconId} icon`} | ||
| className={`flex h-8 w-8 items-center justify-center rounded-md border transition-all ${ | ||
| isSelected | ||
| ? 'border-primary bg-primary/10 text-primary' | ||
| : 'border-border bg-surface text-secondary hover:border-primary/50 hover:text-primary' | ||
| } ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`} | ||
| title={iconId} | ||
| > | ||
| <IconComponent size={16} /> | ||
| </button> | ||
| ); | ||
| })} | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -23,7 +23,7 @@ type MarketFilterProps = { | |||||||||||||||||||||||||||
| variant?: 'ghost' | 'button'; | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| type DetailViewType = 'filter-thresholds' | 'trusted-vaults' | 'trending-config'; | ||||||||||||||||||||||||||||
| type DetailViewType = 'filter-thresholds' | 'trusted-vaults' | 'custom-tag-config'; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export function MarketFilter({ className, variant = 'ghost' }: MarketFilterProps) { | ||||||||||||||||||||||||||||
| const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure(); | ||||||||||||||||||||||||||||
|
|
@@ -48,10 +48,11 @@ export function MarketFilter({ className, variant = 'ghost' }: MarketFilterProps | |||||||||||||||||||||||||||
| usdMinSupply, | ||||||||||||||||||||||||||||
| usdMinBorrow, | ||||||||||||||||||||||||||||
| usdMinLiquidity, | ||||||||||||||||||||||||||||
| trendingConfig, | ||||||||||||||||||||||||||||
| showOfficialTrending, | ||||||||||||||||||||||||||||
| customTagConfig, | ||||||||||||||||||||||||||||
| } = useMarketPreferences(); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const { trendingMode, toggleTrendingMode } = useMarketsFilters(); | ||||||||||||||||||||||||||||
| const { trendingMode, toggleTrendingMode, customTagMode, toggleCustomTagMode } = useMarketsFilters(); | ||||||||||||||||||||||||||||
| const { showUnwhitelistedMarkets, setShowUnwhitelistedMarkets } = useAppSettings(); | ||||||||||||||||||||||||||||
| const { vaults: trustedVaults } = useTrustedVaults(); | ||||||||||||||||||||||||||||
| const trustedVaultCount = trustedVaults.length; | ||||||||||||||||||||||||||||
|
|
@@ -66,7 +67,8 @@ export function MarketFilter({ className, variant = 'ghost' }: MarketFilterProps | |||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const basicGuardianAllAllowed = includeUnknownTokens && showUnknownOracle && showUnwhitelistedMarkets && showLockedMarkets; | ||||||||||||||||||||||||||||
| const advancedFilterActive = trustedVaultsOnly || minSupplyEnabled || minBorrowEnabled || minLiquidityEnabled || trendingMode; | ||||||||||||||||||||||||||||
| const advancedFilterActive = | ||||||||||||||||||||||||||||
| trustedVaultsOnly || minSupplyEnabled || minBorrowEnabled || minLiquidityEnabled || trendingMode || customTagMode; | ||||||||||||||||||||||||||||
| const hasActiveFilters = advancedFilterActive || !basicGuardianAllAllowed; | ||||||||||||||||||||||||||||
|
Comment on lines
69
to
72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gate Proposed fix- const advancedFilterActive = trustedVaultsOnly || minSupplyEnabled || minBorrowEnabled || minLiquidityEnabled || trendingMode || customTagMode;
+ const advancedFilterActive =
+ trustedVaultsOnly ||
+ minSupplyEnabled ||
+ minBorrowEnabled ||
+ minLiquidityEnabled ||
+ (showOfficialTrending && trendingMode) ||
+ (customTagConfig.enabled && customTagMode);π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const isButtonVariant = variant === 'button'; | ||||||||||||||||||||||||||||
|
|
@@ -244,24 +246,39 @@ export function MarketFilter({ className, variant = 'ghost' }: MarketFilterProps | |||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </FilterRow> | ||||||||||||||||||||||||||||
| {trendingConfig.enabled && ( | ||||||||||||||||||||||||||||
| {/* Official Trending Filter (backend-computed) */} | ||||||||||||||||||||||||||||
| {showOfficialTrending && ( | ||||||||||||||||||||||||||||
| <FilterRow | ||||||||||||||||||||||||||||
| title="Trending Only" | ||||||||||||||||||||||||||||
| description="Show markets matching your trending criteria" | ||||||||||||||||||||||||||||
| description="Show officially trending markets" | ||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||
| <IconSwitch | ||||||||||||||||||||||||||||
| selected={trendingMode} | ||||||||||||||||||||||||||||
| onChange={toggleTrendingMode} | ||||||||||||||||||||||||||||
| size="xs" | ||||||||||||||||||||||||||||
| color="primary" | ||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||
| </FilterRow> | ||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||
| {/* Custom Tag Filter (user-defined) */} | ||||||||||||||||||||||||||||
| {customTagConfig.enabled && ( | ||||||||||||||||||||||||||||
| <FilterRow | ||||||||||||||||||||||||||||
| title="Custom Tag Only" | ||||||||||||||||||||||||||||
| description="Show markets matching your custom tag" | ||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||
| <div className="flex items-center gap-1.5"> | ||||||||||||||||||||||||||||
| <Button | ||||||||||||||||||||||||||||
| variant="ghost" | ||||||||||||||||||||||||||||
| size="icon" | ||||||||||||||||||||||||||||
| onClick={() => handleOpenDetailView('trending-config')} | ||||||||||||||||||||||||||||
| aria-label="Configure trending" | ||||||||||||||||||||||||||||
| onClick={() => handleOpenDetailView('custom-tag-config')} | ||||||||||||||||||||||||||||
| aria-label="Configure custom tag" | ||||||||||||||||||||||||||||
| className="h-6 w-6" | ||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||
| <GoGear className="h-3.5 w-3.5" /> | ||||||||||||||||||||||||||||
| </Button> | ||||||||||||||||||||||||||||
| <IconSwitch | ||||||||||||||||||||||||||||
| selected={trendingMode} | ||||||||||||||||||||||||||||
| onChange={toggleTrendingMode} | ||||||||||||||||||||||||||||
| selected={customTagMode} | ||||||||||||||||||||||||||||
| onChange={toggleCustomTagMode} | ||||||||||||||||||||||||||||
| size="xs" | ||||||||||||||||||||||||||||
| color="primary" | ||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.