search redirections, games in landing image fetch, updated filters behavior in the search page, social nav active button switch #40
@ -42535,7 +42535,7 @@ Petrified Demo,,
|
|||||||
Conquer: Napoleonic Wars,,
|
Conquer: Napoleonic Wars,,
|
||||||
ALTAIR BREAKER - ROYAL SET,,
|
ALTAIR BREAKER - ROYAL SET,,
|
||||||
Panique à Temple A-Steak Soundtrack,,
|
Panique à Temple A-Steak Soundtrack,,
|
||||||
Persona 3 Reload,,
|
Persona 3 Reload,,https://image.nostr.build/440a646b13cb9cb95b261eb56dd27ca36a2c7a2caab2571b2605842ea6624d6a.jpg
|
||||||
GigaBash - Godzilla 4 Kaiju Pack,,
|
GigaBash - Godzilla 4 Kaiju Pack,,
|
||||||
Mike's Arcade,,
|
Mike's Arcade,,
|
||||||
STAR WARS Jedi: Survivor™ Deluxe Edition Key,,
|
STAR WARS Jedi: Survivor™ Deluxe Edition Key,,
|
||||||
@ -73896,7 +73896,7 @@ Touhou Endless Dream,,
|
|||||||
Zombie Defense Shelter,,
|
Zombie Defense Shelter,,
|
||||||
Rest House 2 - The Wizard,,
|
Rest House 2 - The Wizard,,
|
||||||
Terraforming Mars - Prelude,,
|
Terraforming Mars - Prelude,,
|
||||||
ELDEN RING,,
|
ELDEN RING,,https://image.nostr.build/6fe622a3594b5d0fa1e80a3d277deebba4e5ca7bd995cc0ab7f17df057423812.jpg
|
||||||
Virage Rally,,
|
Virage Rally,,
|
||||||
Ballavita,,
|
Ballavita,,
|
||||||
Blackstone Academy for the Magical Arts,,
|
Blackstone Academy for the Magical Arts,,
|
||||||
@ -76133,7 +76133,7 @@ The Purification,,
|
|||||||
Xuan-Yuan Sword VII Outfit DLC– Afterglow of Mohists,,
|
Xuan-Yuan Sword VII Outfit DLC– Afterglow of Mohists,,
|
||||||
Dum Dum Dinos Demo,,
|
Dum Dum Dinos Demo,,
|
||||||
Snow Survival,,
|
Snow Survival,,
|
||||||
FINAL FANTASY VII REMAKE INTERGRADE,,
|
FINAL FANTASY VII REMAKE INTERGRADE,,https://image.nostr.build/cc1ae58f1c2fb4c955398eeb0917acc6a88c768d0e02267e2aa30bfb9c92e19c.jpg
|
||||||
Escape from hospital,,
|
Escape from hospital,,
|
||||||
Roots of Evil,,
|
Roots of Evil,,
|
||||||
Dum Dum Dinos,,
|
Dum Dum Dinos,,
|
||||||
@ -95354,7 +95354,7 @@ DLC-富人遗产,,
|
|||||||
DLC-奇妙小屋,,
|
DLC-奇妙小屋,,
|
||||||
Souls of Blades,,
|
Souls of Blades,,
|
||||||
Put In - Run Out,,
|
Put In - Run Out,,
|
||||||
Cyberpunk 2077,,
|
Cyberpunk 2077,,https://image.nostr.build/77e6e989450245630243b4410fea74fa56ed092f95c4c45bc6c949ee3ebc2de7.jpg
|
||||||
Zombie Army 4: Zombie Gentleman Dress Uniform Character,,
|
Zombie Army 4: Zombie Gentleman Dress Uniform Character,,
|
||||||
Zombie Army 4: Berserker Boris Outfit,,
|
Zombie Army 4: Berserker Boris Outfit,,
|
||||||
Zombie Army 4: Holiday Weapon Skins,,
|
Zombie Army 4: Holiday Weapon Skins,,
|
||||||
@ -202716,7 +202716,7 @@ SunnySide,,
|
|||||||
Cloudbuilt,,
|
Cloudbuilt,,
|
||||||
LONESTAR,,
|
LONESTAR,,
|
||||||
Into the Emberlands - Supporter Pack,,
|
Into the Emberlands - Supporter Pack,,
|
||||||
Caravan Sandwitch,,
|
Caravan Sandwitch,,https://s2.ezgif.com/tmp/ezgif-2-a4cdee2a97.jpg
|
||||||
Nine Sols,,
|
Nine Sols,,
|
||||||
Stardeus,,
|
Stardeus,,
|
||||||
Keyboard Tennis Demo,,
|
Keyboard Tennis Demo,,
|
||||||
|
Can't render this file because it is too large.
|
@ -14,26 +14,11 @@ export const LANDING_PAGE_DATA = {
|
|||||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx'
|
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx'
|
||||||
],
|
],
|
||||||
featuredGames: [
|
featuredGames: [
|
||||||
{
|
'Persona 3 Reload',
|
||||||
title: 'SUPERHOT',
|
'Caravan Sandwitch',
|
||||||
imageUrl: ''
|
'Cyberpunk 2077',
|
||||||
},
|
'ELDEN RING',
|
||||||
{
|
'FINAL FANTASY VII REMAKE INTERGRADE'
|
||||||
title: 'The Bounce House',
|
|
||||||
imageUrl: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Immortal Guns',
|
|
||||||
imageUrl: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Magenta Horizon Act 1',
|
|
||||||
imageUrl: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'DEAD LETTER DEPT. Demo',
|
|
||||||
imageUrl: ''
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
// we use this object to check if a user has reacted positively or negatively to a post
|
// we use this object to check if a user has reacted positively or negatively to a post
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
import { appRoutes, getProfilePageRoute } from 'routes'
|
import { appRoutes, getProfilePageRoute } from 'routes'
|
||||||
import 'styles/socialNav.css'
|
import 'styles/socialNav.css'
|
||||||
|
|
||||||
export const SocialNav = () => {
|
export const SocialNav = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const currentPath = location.pathname
|
||||||
const [isCollapsed, setIsCollapsed] = useState<boolean>(false)
|
const [isCollapsed, setIsCollapsed] = useState<boolean>(false)
|
||||||
|
|
||||||
const toggleNav = () => {
|
const toggleNav = () => {
|
||||||
setIsCollapsed(!isCollapsed)
|
setIsCollapsed(!isCollapsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isOnHomePage =
|
||||||
|
currentPath === appRoutes.index || currentPath === appRoutes.home
|
||||||
|
const isOnSearchPage = currentPath === appRoutes.search
|
||||||
|
const isOnProfilePage = new RegExp(
|
||||||
|
`^${appRoutes.profile.replace(':nprofile', '[^/]+')}$`
|
||||||
|
).test(currentPath)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='socialNav'
|
className='socialNav'
|
||||||
@ -21,79 +30,33 @@ export const SocialNav = () => {
|
|||||||
<div className='socialNavInsideWrapper'>
|
<div className='socialNavInsideWrapper'>
|
||||||
{!isCollapsed && (
|
{!isCollapsed && (
|
||||||
<div className='socialNavInside'>
|
<div className='socialNavInside'>
|
||||||
<Link
|
<NavButton
|
||||||
to={appRoutes.home}
|
to={appRoutes.home}
|
||||||
className='btn btnMain socialNavInsideBtn socialNavInsideBtnActive'
|
isActive={isOnHomePage}
|
||||||
>
|
svgPath='M511.8 287.6L512.5 447.7C512.5 450.5 512.3 453.1 512 455.8V472C512 494.1 494.1 512 472 512H456C454.9 512 453.8 511.1 452.7 511.9C451.3 511.1 449.9 512 448.5 512H392C369.9 512 352 494.1 352 472V384C352 366.3 337.7 352 320 352H256C238.3 352 224 366.3 224 384V472C224 494.1 206.1 512 184 512H128.1C126.6 512 125.1 511.9 123.6 511.8C122.4 511.9 121.2 512 120 512H104C81.91 512 64 494.1 64 472V360C64 359.1 64.03 358.1 64.09 357.2V287.6H32.05C14.02 287.6 0 273.5 0 255.5C0 246.5 3.004 238.5 10.01 231.5L266.4 8.016C273.4 1.002 281.4 0 288.4 0C295.4 0 303.4 2.004 309.5 7.014L416 100.7V64C416 46.33 430.3 32 448 32H480C497.7 32 512 46.33 512 64V185L564.8 231.5C572.8 238.5 576.9 246.5 575.8 255.5C575.8 273.5 560.8 287.6 543.8 287.6L511.8 287.6z'
|
||||||
<svg
|
/>
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
<NavButton
|
||||||
viewBox='0 -32 576 576'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M511.8 287.6L512.5 447.7C512.5 450.5 512.3 453.1 512 455.8V472C512 494.1 494.1 512 472 512H456C454.9 512 453.8 511.1 452.7 511.9C451.3 511.1 449.9 512 448.5 512H392C369.9 512 352 494.1 352 472V384C352 366.3 337.7 352 320 352H256C238.3 352 224 366.3 224 384V472C224 494.1 206.1 512 184 512H128.1C126.6 512 125.1 511.9 123.6 511.8C122.4 511.9 121.2 512 120 512H104C81.91 512 64 494.1 64 472V360C64 359.1 64.03 358.1 64.09 357.2V287.6H32.05C14.02 287.6 0 273.5 0 255.5C0 246.5 3.004 238.5 10.01 231.5L266.4 8.016C273.4 1.002 281.4 0 288.4 0C295.4 0 303.4 2.004 309.5 7.014L416 100.7V64C416 46.33 430.3 32 448 32H480C497.7 32 512 46.33 512 64V185L564.8 231.5C572.8 238.5 576.9 246.5 575.8 255.5C575.8 273.5 560.8 287.6 543.8 287.6L511.8 287.6z'></path>
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className='btn btnMain socialNavInsideBtn'
|
|
||||||
to={appRoutes.home}
|
to={appRoutes.home}
|
||||||
>
|
isActive={false}
|
||||||
<svg
|
svgPath='M88 48C101.3 48 112 58.75 112 72V120C112 133.3 101.3 144 88 144H40C26.75 144 16 133.3 16 120V72C16 58.75 26.75 48 40 48H88zM480 64C497.7 64 512 78.33 512 96C512 113.7 497.7 128 480 128H192C174.3 128 160 113.7 160 96C160 78.33 174.3 64 192 64H480zM480 224C497.7 224 512 238.3 512 256C512 273.7 497.7 288 480 288H192C174.3 288 160 273.7 160 256C160 238.3 174.3 224 192 224H480zM480 384C497.7 384 512 398.3 512 416C512 433.7 497.7 448 480 448H192C174.3 448 160 433.7 160 416C160 398.3 174.3 384 192 384H480zM16 232C16 218.7 26.75 208 40 208H88C101.3 208 112 218.7 112 232V280C112 293.3 101.3 304 88 304H40C26.75 304 16 293.3 16 280V232zM88 368C101.3 368 112 378.7 112 392V440C112 453.3 101.3 464 88 464H40C26.75 464 16 453.3 16 440V392C16 378.7 26.75 368 40 368H88z'
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
/>
|
||||||
viewBox='0 0 512 512'
|
<NavButton
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M88 48C101.3 48 112 58.75 112 72V120C112 133.3 101.3 144 88 144H40C26.75 144 16 133.3 16 120V72C16 58.75 26.75 48 40 48H88zM480 64C497.7 64 512 78.33 512 96C512 113.7 497.7 128 480 128H192C174.3 128 160 113.7 160 96C160 78.33 174.3 64 192 64H480zM480 224C497.7 224 512 238.3 512 256C512 273.7 497.7 288 480 288H192C174.3 288 160 273.7 160 256C160 238.3 174.3 224 192 224H480zM480 384C497.7 384 512 398.3 512 416C512 433.7 497.7 448 480 448H192C174.3 448 160 433.7 160 416C160 398.3 174.3 384 192 384H480zM16 232C16 218.7 26.75 208 40 208H88C101.3 208 112 218.7 112 232V280C112 293.3 101.3 304 88 304H40C26.75 304 16 293.3 16 280V232zM88 368C101.3 368 112 378.7 112 392V440C112 453.3 101.3 464 88 464H40C26.75 464 16 453.3 16 440V392C16 378.7 26.75 368 40 368H88z'></path>
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className='btn btnMain socialNavInsideBtn'
|
|
||||||
to={appRoutes.home}
|
to={appRoutes.home}
|
||||||
>
|
isActive={false}
|
||||||
<svg
|
svgPath='M256 32V51.2C329 66.03 384 130.6 384 208V226.8C384 273.9 401.3 319.2 432.5 354.4L439.9 362.7C448.3 372.2 450.4 385.6 445.2 397.1C440 408.6 428.6 416 416 416H32C19.4 416 7.971 408.6 2.809 397.1C-2.353 385.6-.2883 372.2 8.084 362.7L15.5 354.4C46.74 319.2 64 273.9 64 226.8V208C64 130.6 118.1 66.03 192 51.2V32C192 14.33 206.3 0 224 0C241.7 0 256 14.33 256 32H256zM224 512C207 512 190.7 505.3 178.7 493.3C166.7 481.3 160 464.1 160 448H288C288 464.1 281.3 481.3 269.3 493.3C257.3 505.3 240.1 512 224 512z'
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
/>
|
||||||
viewBox='-32 0 512 512'
|
<NavButton
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M256 32V51.2C329 66.03 384 130.6 384 208V226.8C384 273.9 401.3 319.2 432.5 354.4L439.9 362.7C448.3 372.2 450.4 385.6 445.2 397.1C440 408.6 428.6 416 416 416H32C19.4 416 7.971 408.6 2.809 397.1C-2.353 385.6-.2883 372.2 8.084 362.7L15.5 354.4C46.74 319.2 64 273.9 64 226.8V208C64 130.6 118.1 66.03 192 51.2V32C192 14.33 206.3 0 224 0C241.7 0 256 14.33 256 32H256zM224 512C207 512 190.7 505.3 178.7 493.3C166.7 481.3 160 464.1 160 448H288C288 464.1 281.3 481.3 269.3 493.3C257.3 505.3 240.1 512 224 512z'></path>
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className='btn btnMain socialNavInsideBtn'
|
|
||||||
to={appRoutes.search}
|
to={appRoutes.search}
|
||||||
>
|
isActive={isOnSearchPage}
|
||||||
<svg
|
svgPath='M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8 87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08 166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95 15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128 128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z'
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
/>
|
||||||
viewBox='0 0 512 512'
|
<NavButton
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M500.3 443.7l-119.7-119.7c27.22-40.41 40.65-90.9 33.46-144.7C401.8 87.79 326.8 13.32 235.2 1.723C99.01-15.51-15.51 99.01 1.724 235.2c11.6 91.64 86.08 166.7 177.6 178.9c53.8 7.189 104.3-6.236 144.7-33.46l119.7 119.7c15.62 15.62 40.95 15.62 56.57 0C515.9 484.7 515.9 459.3 500.3 443.7zM79.1 208c0-70.58 57.42-128 128-128s128 57.42 128 128c0 70.58-57.42 128-128 128S79.1 278.6 79.1 208z'></path>
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className='btn btnMain socialNavInsideBtn'
|
|
||||||
to={getProfilePageRoute('xyz')}
|
to={getProfilePageRoute('xyz')}
|
||||||
>
|
isActive={isOnProfilePage}
|
||||||
<svg
|
svgPath='M256 288c79.53 0 144-64.47 144-144s-64.47-144-144-144c-79.52 0-144 64.47-144 144S176.5 288 256 288zM351.1 320H160c-88.36 0-160 71.63-160 160c0 17.67 14.33 32 31.1 32H480c17.67 0 31.1-14.33 31.1-32C512 391.6 440.4 320 351.1 320z'
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
/>
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M256 288c79.53 0 144-64.47 144-144s-64.47-144-144-144c-79.52 0-144 64.47-144 144S176.5 288 256 288zM351.1 320H160c-88.36 0-160 71.63-160 160c0 17.67 14.33 32 31.1 32H480c17.67 0 31.1-14.33 31.1-32C512 391.6 440.4 320 351.1 320z'></path>
|
|
||||||
</svg>
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className='socialNavCollapse' onClick={toggleNav}>
|
<div className='socialNavCollapse' onClick={toggleNav}>
|
||||||
<svg
|
<svg
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
@ -113,3 +76,28 @@ export const SocialNav = () => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface NavButtonProps {
|
||||||
|
to: string
|
||||||
|
isActive: boolean
|
||||||
|
svgPath: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NavButton = ({ to, isActive, svgPath }: NavButtonProps) => (
|
||||||
|
<Link
|
||||||
|
to={to}
|
||||||
|
className={`btn btnMain socialNavInsideBtn ${
|
||||||
|
isActive ? 'socialNavInsideBtnActive' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d={svgPath}></path>
|
||||||
|
</svg>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Filter, kinds, nip19 } from 'nostr-tools'
|
import { Filter, kinds, nip19 } from 'nostr-tools'
|
||||||
import { useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { A11y, Navigation, Pagination, Autoplay } from 'swiper/modules'
|
import { A11y, Navigation, Pagination, Autoplay } from 'swiper/modules'
|
||||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||||
@ -8,7 +8,7 @@ import { GameCard } from '../components/GameCard'
|
|||||||
import { ModCard } from '../components/ModCard'
|
import { ModCard } from '../components/ModCard'
|
||||||
import { LANDING_PAGE_DATA } from '../constants'
|
import { LANDING_PAGE_DATA } from '../constants'
|
||||||
import { RelayController } from '../controllers'
|
import { RelayController } from '../controllers'
|
||||||
import { useDidMount } from '../hooks'
|
import { useDidMount, useGames } from '../hooks'
|
||||||
import { appRoutes, getModPageRoute } from '../routes'
|
import { appRoutes, getModPageRoute } from '../routes'
|
||||||
import { ModDetails } from '../types'
|
import { ModDetails } from '../types'
|
||||||
import {
|
import {
|
||||||
@ -30,6 +30,14 @@ import 'swiper/css/pagination'
|
|||||||
|
|
||||||
export const HomePage = () => {
|
export const HomePage = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const games = useGames()
|
||||||
|
|
||||||
|
const featuredGames = useMemo(() => {
|
||||||
|
return games.filter((game) =>
|
||||||
|
LANDING_PAGE_DATA.featuredGames.includes(game['Game Name'])
|
||||||
|
)
|
||||||
|
}, [games])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='InnerBodyMain'>
|
<div className='InnerBodyMain'>
|
||||||
<div className='SliderWrapper'>
|
<div className='SliderWrapper'>
|
||||||
@ -67,11 +75,11 @@ export const HomePage = () => {
|
|||||||
<h2 className='IBMSMTitleMainHeading'>Cool Games</h2>
|
<h2 className='IBMSMTitleMainHeading'>Cool Games</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className='IBMSMList IBMSMListFeaturedAlt'>
|
<div className='IBMSMList IBMSMListFeaturedAlt'>
|
||||||
{LANDING_PAGE_DATA.featuredGames.map((game) => (
|
{featuredGames.map((game) => (
|
||||||
<GameCard
|
<GameCard
|
||||||
key={game.title}
|
key={game['Game Name']}
|
||||||
title={game.title}
|
title={game['Game Name']}
|
||||||
imageUrl={game.imageUrl}
|
imageUrl={game['Boxart image']}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,14 +6,16 @@ import React, {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react'
|
} from 'react'
|
||||||
|
import { createSearchParams, useNavigate } from 'react-router-dom'
|
||||||
import { LoadingSpinner } from '../components/LoadingSpinner'
|
import { LoadingSpinner } from '../components/LoadingSpinner'
|
||||||
import { ModCard } from '../components/ModCard'
|
import { ModCard } from '../components/ModCard'
|
||||||
import { MOD_FILTER_LIMIT } from '../constants'
|
import { MOD_FILTER_LIMIT } from '../constants'
|
||||||
import { MetadataController } from '../controllers'
|
import { MetadataController } from '../controllers'
|
||||||
import { useAppSelector, useDidMount, useMuteLists } from '../hooks'
|
import { useAppSelector, useDidMount, useMuteLists } from '../hooks'
|
||||||
import { getModPageRoute } from '../routes'
|
import { appRoutes, getModPageRoute } from '../routes'
|
||||||
import '../styles/filters.css'
|
import '../styles/filters.css'
|
||||||
import '../styles/pagination.css'
|
import '../styles/pagination.css'
|
||||||
import '../styles/search.css'
|
import '../styles/search.css'
|
||||||
@ -227,6 +229,27 @@ export const ModsPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PageTitleRow = React.memo(() => {
|
const PageTitleRow = React.memo(() => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const searchTermRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
const value = searchTermRef.current?.value || '' // Access the input value from the ref
|
||||||
|
if (value !== '') {
|
||||||
|
const searchParams = createSearchParams({
|
||||||
|
searchTerm: value,
|
||||||
|
searching: 'Mods'
|
||||||
|
})
|
||||||
|
navigate({ pathname: appRoutes.search, search: `?${searchParams}` })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle "Enter" key press inside the input
|
||||||
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='IBMSecMain'>
|
<div className='IBMSecMain'>
|
||||||
<div className='SearchMainWrapper'>
|
<div className='SearchMainWrapper'>
|
||||||
@ -236,8 +259,19 @@ const PageTitleRow = React.memo(() => {
|
|||||||
<div className='SearchMain'>
|
<div className='SearchMain'>
|
||||||
<div className='SearchMainInside'>
|
<div className='SearchMainInside'>
|
||||||
<div className='SearchMainInsideWrapper'>
|
<div className='SearchMainInsideWrapper'>
|
||||||
<input type='text' className='SMIWInput' />
|
<input
|
||||||
<button className='btn btnMain SMIWButton' type='button'>
|
type='text'
|
||||||
|
className='SMIWInput'
|
||||||
|
ref={searchTermRef}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
placeholder='Enter search term'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className='btn btnMain SMIWButton'
|
||||||
|
type='button'
|
||||||
|
onClick={handleSearch}
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
viewBox='0 0 512 512'
|
viewBox='0 0 512 512'
|
||||||
|
@ -51,6 +51,7 @@ interface FilterOptions {
|
|||||||
sort: SortByEnum
|
sort: SortByEnum
|
||||||
moderated: ModeratedFilterEnum
|
moderated: ModeratedFilterEnum
|
||||||
searching: SearchingFilterEnum
|
searching: SearchingFilterEnum
|
||||||
|
source: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SearchPage = () => {
|
export const SearchPage = () => {
|
||||||
@ -61,6 +62,7 @@ export const SearchPage = () => {
|
|||||||
const [filterOptions, setFilterOptions] = useState<FilterOptions>({
|
const [filterOptions, setFilterOptions] = useState<FilterOptions>({
|
||||||
sort: SortByEnum.Latest,
|
sort: SortByEnum.Latest,
|
||||||
moderated: ModeratedFilterEnum.Moderated,
|
moderated: ModeratedFilterEnum.Moderated,
|
||||||
|
source: window.location.host,
|
||||||
searching:
|
searching:
|
||||||
(searchParams.get('searching') as SearchingFilterEnum) ||
|
(searchParams.get('searching') as SearchingFilterEnum) ||
|
||||||
SearchingFilterEnum.Mods
|
SearchingFilterEnum.Mods
|
||||||
@ -164,73 +166,121 @@ const Filters = React.memo(
|
|||||||
return (
|
return (
|
||||||
<div className='IBMSecMain'>
|
<div className='IBMSecMain'>
|
||||||
<div className='FiltersMain'>
|
<div className='FiltersMain'>
|
||||||
<div className='FiltersMainElement'>
|
{filterOptions.searching === SearchingFilterEnum.Mods && (
|
||||||
<div className='dropdown dropdownMain'>
|
<div className='FiltersMainElement'>
|
||||||
<button
|
<div className='dropdown dropdownMain'>
|
||||||
className='btn dropdown-toggle btnMain btnMainDropdown'
|
<button
|
||||||
aria-expanded='false'
|
className='btn dropdown-toggle btnMain btnMainDropdown'
|
||||||
data-bs-toggle='dropdown'
|
aria-expanded='false'
|
||||||
type='button'
|
data-bs-toggle='dropdown'
|
||||||
>
|
type='button'
|
||||||
{filterOptions.sort}
|
>
|
||||||
</button>
|
{filterOptions.sort}
|
||||||
|
</button>
|
||||||
|
|
||||||
<div className='dropdown-menu dropdownMainMenu'>
|
<div className='dropdown-menu dropdownMainMenu'>
|
||||||
{Object.values(SortByEnum).map((item, index) => (
|
{Object.values(SortByEnum).map((item, index) => (
|
||||||
<div
|
|
||||||
key={`sortByItem-${index}`}
|
|
||||||
className='dropdown-item dropdownMainMenuItem'
|
|
||||||
onClick={() =>
|
|
||||||
setFilterOptions((prev) => ({
|
|
||||||
...prev,
|
|
||||||
sort: item
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='FiltersMainElement'>
|
|
||||||
<div className='dropdown dropdownMain'>
|
|
||||||
<button
|
|
||||||
className='btn dropdown-toggle btnMain btnMainDropdown'
|
|
||||||
aria-expanded='false'
|
|
||||||
data-bs-toggle='dropdown'
|
|
||||||
type='button'
|
|
||||||
>
|
|
||||||
{filterOptions.moderated}
|
|
||||||
</button>
|
|
||||||
<div className='dropdown-menu dropdownMainMenu'>
|
|
||||||
{Object.values(ModeratedFilterEnum).map((item, index) => {
|
|
||||||
if (item === ModeratedFilterEnum.Unmoderated_Fully) {
|
|
||||||
const isAdmin =
|
|
||||||
userState.user?.npub ===
|
|
||||||
import.meta.env.VITE_REPORTING_NPUB
|
|
||||||
|
|
||||||
if (!isAdmin) return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
<div
|
||||||
key={`moderatedFilterItem-${index}`}
|
key={`sortByItem-${index}`}
|
||||||
className='dropdown-item dropdownMainMenuItem'
|
className='dropdown-item dropdownMainMenuItem'
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setFilterOptions((prev) => ({
|
setFilterOptions((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
moderated: item
|
sort: item
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{item}
|
{item}
|
||||||
</div>
|
</div>
|
||||||
)
|
))}
|
||||||
})}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
|
{(filterOptions.searching === SearchingFilterEnum.Mods ||
|
||||||
|
filterOptions.searching === SearchingFilterEnum.Users) && (
|
||||||
|
<div className='FiltersMainElement'>
|
||||||
|
<div className='dropdown dropdownMain'>
|
||||||
|
<button
|
||||||
|
className='btn dropdown-toggle btnMain btnMainDropdown'
|
||||||
|
aria-expanded='false'
|
||||||
|
data-bs-toggle='dropdown'
|
||||||
|
type='button'
|
||||||
|
>
|
||||||
|
{filterOptions.moderated}
|
||||||
|
</button>
|
||||||
|
<div className='dropdown-menu dropdownMainMenu'>
|
||||||
|
{Object.values(ModeratedFilterEnum).map((item, index) => {
|
||||||
|
if (item === ModeratedFilterEnum.Unmoderated_Fully) {
|
||||||
|
const isAdmin =
|
||||||
|
userState.user?.npub ===
|
||||||
|
import.meta.env.VITE_REPORTING_NPUB
|
||||||
|
|
||||||
|
if (!isAdmin) return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={`moderatedFilterItem-${index}`}
|
||||||
|
className='dropdown-item dropdownMainMenuItem'
|
||||||
|
onClick={() =>
|
||||||
|
setFilterOptions((prev) => ({
|
||||||
|
...prev,
|
||||||
|
moderated: item
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{filterOptions.searching === SearchingFilterEnum.Mods && (
|
||||||
|
<div className='FiltersMainElement'>
|
||||||
|
<div className='dropdown dropdownMain'>
|
||||||
|
<button
|
||||||
|
className='btn dropdown-toggle btnMain btnMainDropdown'
|
||||||
|
aria-expanded='false'
|
||||||
|
data-bs-toggle='dropdown'
|
||||||
|
type='button'
|
||||||
|
>
|
||||||
|
{filterOptions.source === window.location.host
|
||||||
|
? `Show From: ${filterOptions.source}`
|
||||||
|
: 'Show All'}
|
||||||
|
</button>
|
||||||
|
<div className='dropdown-menu dropdownMainMenu'>
|
||||||
|
<div
|
||||||
|
className='dropdown-item dropdownMainMenuItem'
|
||||||
|
onClick={() =>
|
||||||
|
setFilterOptions((prev) => ({
|
||||||
|
...prev,
|
||||||
|
source: window.location.host
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show From: {window.location.host}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='dropdown-item dropdownMainMenuItem'
|
||||||
|
onClick={() =>
|
||||||
|
setFilterOptions((prev) => ({
|
||||||
|
...prev,
|
||||||
|
source: 'Show All'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Show All
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='FiltersMainElement'>
|
<div className='FiltersMainElement'>
|
||||||
<div className='dropdown dropdownMain'>
|
<div className='dropdown dropdownMain'>
|
||||||
<button
|
<button
|
||||||
@ -353,6 +403,11 @@ const ModsResult = ({
|
|||||||
|
|
||||||
const filteredModList = useMemo(() => {
|
const filteredModList = useMemo(() => {
|
||||||
let filtered: ModDetails[] = [...filteredMods]
|
let filtered: ModDetails[] = [...filteredMods]
|
||||||
|
|
||||||
|
if (filterOptions.source === window.location.host) {
|
||||||
|
filtered = filtered.filter((mod) => mod.rTag === window.location.host)
|
||||||
|
}
|
||||||
|
|
||||||
const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
|
const isAdmin = userState.user?.npub === import.meta.env.VITE_REPORTING_NPUB
|
||||||
const isUnmoderatedFully =
|
const isUnmoderatedFully =
|
||||||
filterOptions.moderated === ModeratedFilterEnum.Unmoderated_Fully
|
filterOptions.moderated === ModeratedFilterEnum.Unmoderated_Fully
|
||||||
@ -386,6 +441,7 @@ const ModsResult = ({
|
|||||||
userState.user?.npub,
|
userState.user?.npub,
|
||||||
filterOptions.sort,
|
filterOptions.sort,
|
||||||
filterOptions.moderated,
|
filterOptions.moderated,
|
||||||
|
filterOptions.source,
|
||||||
muteLists
|
muteLists
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -497,3 +497,79 @@ hover {
|
|||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentRepost {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
grid-gap: 0px;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentRepostVisual {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 50px;
|
||||||
|
color: rgba(255,255,255,0.51);
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentRepostText {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
grid-gap: 5px;
|
||||||
|
color: rgba(255,255,255,0.5);
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
padding: 5px 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentRepostText > a {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentWrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
grid-gap: 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CommentQP {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: solid 1px rgba(255,255,255,0.1);
|
||||||
|
background: rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CBExpand {
|
||||||
|
transition: ease 0.3s;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 5px 15px;
|
||||||
|
background: rgba(255,255,255,0);
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255,255,255,0.25);
|
||||||
|
line-height: 1.5;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IBMSMSMBSSCL_CBExpand:hover {
|
||||||
|
transition: ease 0.3s;
|
||||||
|
background: rgba(255,255,255,0.05);
|
||||||
|
color: rgba(255,255,255,0.25);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user