Merge pull request 'Can now modify landing page. Fallback images for games and mods. Cached events.' (#29) from staging into master
All checks were successful
Release to Staging / build_and_release (push) Successful in 44s
All checks were successful
Release to Staging / build_and_release (push) Successful in 44s
Reviewed-on: #29
This commit is contained in:
commit
0e08d09717
@ -6,3 +6,9 @@ VITE_ADMIN_NPUBS= <A comma separated list of npubs>
|
||||
|
||||
# A dedicated npub used for reporting mods, blogs, profile and etc.
|
||||
VITE_REPORTING_NPUB= <npub1...>
|
||||
|
||||
# if there's no featured image, or if the image breaks somewhere down the line, then it should default to this image
|
||||
VITE_FALLBACK_MOD_IMAGE=https://image.nostr.build/1fa7afd3489302c2da8957993ac0fd6c4308eedd4b1b95b24ecfabe3651b2183.png
|
||||
|
||||
# if there's no image, or if the image breaks somewhere down the line, then it should default to this image
|
||||
VITE_FALLBACK_GAME_IMAGE=https://image.nostr.build/1fa7afd3489302c2da8957993ac0fd6c4308eedd4b1b95b24ecfabe3651b2183.png
|
@ -25,6 +25,8 @@ jobs:
|
||||
echo "VITE_APP_RELAY=${{ vars.VITE_APP_RELAY }}" >> .env
|
||||
echo "VITE_ADMIN_NPUBS=${{ vars.VITE_ADMIN_NPUBS }}" >> .env
|
||||
echo "VITE_REPORTING_NPUB=${{ vars.VITE_REPORTING_NPUB }}" >> .env
|
||||
echo "VITE_FALLBACK_MOD_IMAGE=${{ vars.VITE_FALLBACK_MOD_IMAGE }}" >> .env
|
||||
echo "VITE_FALLBACK_GAME_IMAGE=${{ vars.VITE_FALLBACK_GAME_IMAGE }}" >> .env
|
||||
cat .env
|
||||
|
||||
- name: Create Build
|
||||
|
@ -25,6 +25,8 @@ jobs:
|
||||
echo "VITE_APP_RELAY=${{ vars.VITE_APP_RELAY }}" >> .env
|
||||
echo "VITE_ADMIN_NPUBS=${{ vars.VITE_ADMIN_NPUBS }}" >> .env
|
||||
echo "VITE_REPORTING_NPUB=${{ vars.VITE_REPORTING_NPUB }}" >> .env
|
||||
echo "VITE_FALLBACK_MOD_IMAGE=${{ vars.VITE_FALLBACK_MOD_IMAGE }}" >> .env
|
||||
echo "VITE_FALLBACK_GAME_IMAGE=${{ vars.VITE_FALLBACK_GAME_IMAGE }}" >> .env
|
||||
cat .env
|
||||
|
||||
- name: Create Build
|
||||
|
26
index.html
26
index.html
@ -6,7 +6,10 @@
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="DEG Mods - Liberating Game Mods" />
|
||||
<meta property="og:description" content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely." />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely."
|
||||
/>
|
||||
<meta property="og:image" content="/assets/img/DEGM%20Thumb.png" />
|
||||
<meta property="og:url" content="https://degmods.com" />
|
||||
<meta property="og:type" content="website" />
|
||||
@ -14,24 +17,33 @@
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="DEG Mods - Liberating Game Mods" />
|
||||
<meta name="twitter:description" content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely." />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely."
|
||||
/>
|
||||
<meta name="twitter:image" content="/assets/img/DEGM%20Thumb.png" />
|
||||
|
||||
<!-- Other Meta Tags -->
|
||||
<meta name="description" content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely." />
|
||||
<meta
|
||||
name="description"
|
||||
content="Never get your game mods censored, get banned, lose your history, nor lose the connection between game mod creators and fans. Download your mods freely."
|
||||
/>
|
||||
|
||||
<!-- Links and Stylesheets -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/6.4.8/swiper-bundle.min.css" />
|
||||
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="/assets/fonts/fontawesome-all.min.css" />
|
||||
<link rel="icon" type="image/png" sizes="935x934" href="/assets/img/Logo%20with%20circle.png" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="935x934"
|
||||
href="/assets/img/Logo%20with%20circle.png"
|
||||
/>
|
||||
|
||||
<title>DEG Mods - Liberating Game Mods</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/6.4.8/swiper-bundle.min.js"></script>
|
||||
<script src="assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="/assets/bootstrap/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
19
package-lock.json
generated
19
package-lock.json
generated
@ -34,6 +34,7 @@
|
||||
"react-router-dom": "^6.24.1",
|
||||
"react-toastify": "10.0.5",
|
||||
"react-window": "1.8.10",
|
||||
"swiper": "11.1.11",
|
||||
"uuid": "10.0.0",
|
||||
"webln": "0.3.2"
|
||||
},
|
||||
@ -4932,6 +4933,24 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/swiper": {
|
||||
"version": "11.1.11",
|
||||
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz",
|
||||
"integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/swiperjs"
|
||||
},
|
||||
{
|
||||
"type": "open_collective",
|
||||
"url": "http://opencollective.com/swiper"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 4.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
|
@ -36,6 +36,7 @@
|
||||
"react-router-dom": "^6.24.1",
|
||||
"react-toastify": "10.0.5",
|
||||
"react-window": "1.8.10",
|
||||
"swiper": "11.1.11",
|
||||
"uuid": "10.0.0",
|
||||
"webln": "0.3.2"
|
||||
},
|
||||
|
@ -1,20 +1,23 @@
|
||||
import '../styles/cardGames.css'
|
||||
import { handleGameImageError } from '../utils'
|
||||
|
||||
type GameCardProps = {
|
||||
backgroundLink: string
|
||||
title: string
|
||||
imageUrl: string
|
||||
}
|
||||
|
||||
export const GameCard = ({ backgroundLink }: GameCardProps) => {
|
||||
export const GameCard = ({ title, imageUrl }: GameCardProps) => {
|
||||
return (
|
||||
<a className='cardGameMainWrapperLink' href='search.html'>
|
||||
<div
|
||||
<div className='cardGameMainWrapper'>
|
||||
<img
|
||||
src={imageUrl}
|
||||
onError={handleGameImageError}
|
||||
className='cardGameMain'
|
||||
style={{
|
||||
background: `url("${backgroundLink}") center / cover no-repeat`
|
||||
}}
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
<div className='cardGameMainTitle'>
|
||||
<p>This is a game title, the best game title</p>
|
||||
<p>{title}</p>
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
|
@ -1,9 +1,10 @@
|
||||
import '../styles/cardMod.css'
|
||||
import { handleModImageError } from '../utils'
|
||||
|
||||
type ModCardProps = {
|
||||
title: string
|
||||
summary: string
|
||||
backgroundLink: string
|
||||
imageUrl: string
|
||||
link: string
|
||||
handleClick: () => void
|
||||
}
|
||||
@ -11,7 +12,7 @@ type ModCardProps = {
|
||||
export const ModCard = ({
|
||||
title,
|
||||
summary,
|
||||
backgroundLink,
|
||||
imageUrl,
|
||||
link,
|
||||
handleClick
|
||||
}: ModCardProps) => {
|
||||
@ -25,12 +26,13 @@ export const ModCard = ({
|
||||
}}
|
||||
>
|
||||
<div className='cardModMain'>
|
||||
<div
|
||||
<div className='cMMPictureWrapper'>
|
||||
<img
|
||||
src={imageUrl}
|
||||
onError={handleModImageError}
|
||||
className='cMMPicture'
|
||||
style={{
|
||||
background: `url("${backgroundLink}") center / cover no-repeat`
|
||||
}}
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
<div className='cMMBody'>
|
||||
<h3 className='cMMBodyTitle'>{title}</h3>
|
||||
<p className='cMMBodyText'>{summary}</p>
|
||||
|
@ -1,2 +1,38 @@
|
||||
export const T_TAG_VALUE = 'GameMod'
|
||||
export const MOD_FILTER_LIMIT = 20
|
||||
export const LANDING_PAGE_DATA = {
|
||||
featuredSlider: [
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5cek8pnrwc34xgknyv33xqkngc34xyknscfjxsknzvp38quxgc33vejnqvqhqecq8',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vpcxs6nwwp3x5knyd3evckngetxxcknjdfkx5kngdfhvgukvwfjxsunseqnend73',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5d3excenzvf5xgkkvdny8qkngveex5knjcnxxqkn2efnx3jrxvpcxgukxdggsmal6',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5dp4xsex2e3cxuknsdryvvkngc3sxcknjef4vcknvvmyvcukyd3kvd3rxdgnuver5',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vf5x9nrxcekxvknjvmzxvkngcfsx5kkzcf3xqknsvmrvgenwe3j8p3nzwgka59vj'
|
||||
],
|
||||
awesomeMods: [
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5d3excenzvf5xgkkvdny8qkngveex5knjcnxxqkn2efnx3jrxvpcxgukxdggsmal6',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5df5xccngvtrxqkkydpexukngvp4xgknsvp4vskkgdrxvgmkxdmp8quxycgx78rpf',
|
||||
'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx'
|
||||
],
|
||||
featuredGames: [
|
||||
{
|
||||
title: 'SUPERHOT',
|
||||
imageUrl: ''
|
||||
},
|
||||
{
|
||||
title: 'The Bounce House',
|
||||
imageUrl: ''
|
||||
},
|
||||
{
|
||||
title: 'Immortal Guns',
|
||||
imageUrl: ''
|
||||
},
|
||||
{
|
||||
title: 'Magenta Horizon Act 1',
|
||||
imageUrl: ''
|
||||
},
|
||||
{
|
||||
title: 'DEAD LETTER DEPT. Demo',
|
||||
imageUrl: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import { MetadataController, UserRelaysType } from './metadata'
|
||||
*/
|
||||
export class RelayController {
|
||||
private static instance: RelayController
|
||||
private events = new Map<string, Event>()
|
||||
private debug = true
|
||||
public connectedRelays: Relay[] = []
|
||||
|
||||
@ -151,6 +152,16 @@ export class RelayController {
|
||||
// Wait for all publish operations to complete (either fulfilled or rejected)
|
||||
await Promise.allSettled(publishPromises)
|
||||
|
||||
if (publishedOnRelays.length > 0) {
|
||||
// if the event was successfully published to relays then check if it contains the `aTag`
|
||||
// if so, then cache the event
|
||||
|
||||
const aTag = event.tags.find((item) => item[0] === 'a')
|
||||
if (aTag && aTag[1]) {
|
||||
this.events.set(aTag[1], event)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the list of relay URLs where the event was published
|
||||
return publishedOnRelays
|
||||
}
|
||||
@ -335,13 +346,35 @@ export class RelayController {
|
||||
filter: Filter,
|
||||
relays: string[] = []
|
||||
): Promise<Event | null> => {
|
||||
// first check if event is present in cached map then return that
|
||||
// otherwise query relays
|
||||
if (filter['#a']) {
|
||||
const aTag = filter['#a'][0]
|
||||
const cachedEvent = this.events.get(aTag)
|
||||
|
||||
if (cachedEvent) return cachedEvent
|
||||
}
|
||||
|
||||
const events = await this.fetchEvents(filter, relays)
|
||||
|
||||
// Sort events by creation date in descending order
|
||||
events.sort((a, b) => b.created_at - a.created_at)
|
||||
|
||||
// Return the most recent event, or null if no events were received
|
||||
return events[0] || null
|
||||
if (events.length > 0) {
|
||||
const event = events[0]
|
||||
|
||||
// if the aTag was specified in filter then cache the fetched event before returning
|
||||
if (filter['#a']) {
|
||||
const aTag = filter['#a'][0]
|
||||
this.events.set(aTag, event)
|
||||
}
|
||||
|
||||
// return the event
|
||||
return event
|
||||
}
|
||||
|
||||
// return null if event array is empty
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -358,6 +391,15 @@ export class RelayController {
|
||||
hexKey: string,
|
||||
userRelaysType: UserRelaysType
|
||||
) => {
|
||||
// first check if event is present in cached map then return that
|
||||
// otherwise query relays
|
||||
if (filter['#a']) {
|
||||
const aTag = filter['#a'][0]
|
||||
const cachedEvent = this.events.get(aTag)
|
||||
|
||||
if (cachedEvent) return cachedEvent
|
||||
}
|
||||
|
||||
// Get an instance of the MetadataController, which manages user metadata and relays
|
||||
const metadataController = await MetadataController.getInstance()
|
||||
|
||||
|
@ -35,11 +35,26 @@ export const GamesPage = () => {
|
||||
</div>
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMList IBMSMListFeaturedAlt'>
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard
|
||||
title='This is a game title, the best game title'
|
||||
imageUrl='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
/>
|
||||
<GameCard
|
||||
title='This is a game title, the best game title'
|
||||
imageUrl='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
/>
|
||||
<GameCard
|
||||
title='This is a game title, the best game title'
|
||||
imageUrl='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
/>
|
||||
<GameCard
|
||||
title='This is a game title, the best game title'
|
||||
imageUrl='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
/>
|
||||
<GameCard
|
||||
title='This is a game title, the best game title'
|
||||
imageUrl='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='IBMSecMain'>
|
||||
|
@ -1,123 +1,58 @@
|
||||
import { Filter, kinds, nip19 } from 'nostr-tools'
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { A11y, Navigation, Pagination } from 'swiper/modules'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import { BlogCard } from '../components/BlogCard'
|
||||
import { GameCard } from '../components/GameCard'
|
||||
import { ModCard } from '../components/ModCard'
|
||||
import { LANDING_PAGE_DATA } from '../constants'
|
||||
import { RelayController } from '../controllers'
|
||||
import { useDidMount } from '../hooks'
|
||||
import { appRoutes, getModsInnerPageRoute } from '../routes'
|
||||
import { ModDetails } from '../types'
|
||||
import {
|
||||
extractModData,
|
||||
fetchMods,
|
||||
handleModImageError,
|
||||
log,
|
||||
LogType
|
||||
} from '../utils'
|
||||
|
||||
import '../styles/cardLists.css'
|
||||
import '../styles/SimpleSlider.css'
|
||||
import '../styles/styles.css'
|
||||
|
||||
// Import Swiper styles
|
||||
import 'swiper/css'
|
||||
import 'swiper/css/navigation'
|
||||
import 'swiper/css/pagination'
|
||||
|
||||
export const HomePage = () => {
|
||||
const navigate = useNavigate()
|
||||
return (
|
||||
<div className='InnerBodyMain'>
|
||||
<div className='SliderWrapper'>
|
||||
<div className='ContainerMain'>
|
||||
<div className='IBMSecMain'>
|
||||
<div className='simple-slider IBMSMSlider'>
|
||||
<div className='swiper-container IBMSMSliderContainer'>
|
||||
<div className='swiper-wrapper IBMSMSliderContainerWrapper'>
|
||||
<div className='swiper-slide IBMSMSliderContainerWrapperSlider'>
|
||||
<div
|
||||
className='IBMSMSCWSPic'
|
||||
style={{
|
||||
background:
|
||||
'url("/assets/img/DEGMods%20Placeholder%20Img.png") center / cover no-repeat'
|
||||
}}
|
||||
></div>
|
||||
<div className='IBMSMSCWSInfo'>
|
||||
<h3 className='IBMSMSCWSInfoHeading'>Placeholder</h3>
|
||||
<p className='IBMSMSCWSInfoText'>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Integer nec odio. Praesent libero. Sed cursus ante
|
||||
dapibus diam. Sed nisi. Nulla quis sem at nibh elementum
|
||||
imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce
|
||||
nec tellus sed augue semper porta. Mauris massa.
|
||||
Vestibulum lacinia arcu eget nulla. className aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Curabitur sodales ligula in
|
||||
libero.
|
||||
<br />
|
||||
</p>
|
||||
<div className='IBMSMSliderContainerWrapperSliderAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMSliderContainerWrapperSliderActionbtn'
|
||||
role='button'
|
||||
href='mods-inner.html'
|
||||
<Swiper
|
||||
className='swiper-container IBMSMSliderContainer'
|
||||
wrapperClass='swiper-wrapper IBMSMSliderContainerWrapper'
|
||||
modules={[Navigation, Pagination, A11y]}
|
||||
pagination={{ clickable: true, dynamicBullets: true }}
|
||||
slidesPerView={1}
|
||||
autoplay={{ delay: 5000 }}
|
||||
speed={1000}
|
||||
navigation
|
||||
loop
|
||||
>
|
||||
Check it out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='swiper-slide IBMSMSliderContainerWrapperSlider'>
|
||||
<div
|
||||
className='IBMSMSCWSPic'
|
||||
style={{
|
||||
background:
|
||||
'url("/assets/img/DEGMods%20Placeholder%20Img.png") center / cover no-repeat'
|
||||
}}
|
||||
></div>
|
||||
<div className='IBMSMSCWSInfo'>
|
||||
<h3 className='IBMSMSCWSInfoHeading'>Placeholder</h3>
|
||||
<p className='IBMSMSCWSInfoText'>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Integer nec odio. Praesent libero. Sed cursus ante
|
||||
dapibus diam. Sed nisi. Nulla quis sem at nibh elementum
|
||||
imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce
|
||||
nec tellus sed augue semper porta. Mauris massa.
|
||||
Vestibulum lacinia arcu eget nulla. className aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Curabitur sodales ligula in
|
||||
libero.
|
||||
<br />
|
||||
</p>
|
||||
<div className='IBMSMSliderContainerWrapperSliderAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMSliderContainerWrapperSliderActionbtn'
|
||||
role='button'
|
||||
href='mods-inner.html'
|
||||
>
|
||||
Check it out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='swiper-slide IBMSMSliderContainerWrapperSlider'>
|
||||
<div
|
||||
className='IBMSMSCWSPic'
|
||||
style={{
|
||||
background:
|
||||
'url("/assets/img/DEGMods%20Placeholder%20Img.png") center / cover no-repeat'
|
||||
}}
|
||||
></div>
|
||||
<div className='IBMSMSCWSInfo'>
|
||||
<h3 className='IBMSMSCWSInfoHeading'>Placeholder</h3>
|
||||
<p className='IBMSMSCWSInfoText'>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Integer nec odio. Praesent libero. Sed cursus ante
|
||||
dapibus diam. Sed nisi. Nulla quis sem at nibh elementum
|
||||
imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce
|
||||
nec tellus sed augue semper porta. Mauris massa.
|
||||
Vestibulum lacinia arcu eget nulla. className aptent
|
||||
taciti sociosqu ad litora torquent per conubia nostra,
|
||||
per inceptos himenaeos. Curabitur sodales ligula in
|
||||
libero.
|
||||
<br />
|
||||
</p>
|
||||
<div className='IBMSMSliderContainerWrapperSliderAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMSliderContainerWrapperSliderActionbtn'
|
||||
role='button'
|
||||
href='mods-inner.html'
|
||||
>
|
||||
Check it out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='swiper-pagination'></div>
|
||||
<div className='swiper-button-prev'></div>
|
||||
<div className='swiper-button-next'></div>
|
||||
</div>
|
||||
{LANDING_PAGE_DATA.featuredSlider.map((naddr) => (
|
||||
<SwiperSlide className='swiper-slide IBMSMSliderContainerWrapperSlider'>
|
||||
<SlideContent naddr={naddr} />
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -126,20 +61,18 @@ export const HomePage = () => {
|
||||
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Cool Games (WIP)</h2>
|
||||
<h2 className='IBMSMTitleMainHeading'>Cool Games</h2>
|
||||
</div>
|
||||
<div className='IBMSMList IBMSMListFeaturedAlt'>
|
||||
<GameCard backgroundLink='assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
<GameCard backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png' />
|
||||
{LANDING_PAGE_DATA.featuredGames.map((game) => (
|
||||
<GameCard title={game.title} imageUrl={game.imageUrl} />
|
||||
))}
|
||||
</div>
|
||||
<div className='IBMSMAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
href='blog.html'
|
||||
onClick={() => navigate(appRoutes.games)}
|
||||
>
|
||||
View All
|
||||
</a>
|
||||
@ -147,114 +80,24 @@ export const HomePage = () => {
|
||||
</div>
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Awesome Mods (WIP)</h2>
|
||||
<h2 className='IBMSMTitleMainHeading'>Awesome Mods</h2>
|
||||
</div>
|
||||
<div className='IBMSMList IBMSMListAlt'>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
{LANDING_PAGE_DATA.awesomeMods.map((naddr) => (
|
||||
<DisplayMod key={naddr} naddr={naddr} />
|
||||
))}
|
||||
</div>
|
||||
<div className='IBMSMAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
href='blog.html'
|
||||
>
|
||||
View All
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Latest Mods (WIP)</h2>
|
||||
</div>
|
||||
<div className='IBMSMList'>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<ModCard
|
||||
title='Placeholder'
|
||||
summary='Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
||||
backgroundLink='/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||
link=''
|
||||
handleClick={() => {
|
||||
alert(
|
||||
'these are dummy mods. So navigation on these are not implemented yet'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='IBMSMAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
href='blog.html'
|
||||
onClick={() => navigate(appRoutes.mods)}
|
||||
>
|
||||
View All
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<DisplayLatestMods />
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Blog Posts (WIP)</h2>
|
||||
@ -281,3 +124,189 @@ export const HomePage = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
type SlideContentProps = {
|
||||
naddr: string
|
||||
}
|
||||
|
||||
const SlideContent = ({ naddr }: SlideContentProps) => {
|
||||
const navigate = useNavigate()
|
||||
const [mod, setMod] = useState<ModDetails>()
|
||||
|
||||
useDidMount(() => {
|
||||
const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`)
|
||||
const { identifier, kind, pubkey, relays = [] } = decoded.data
|
||||
|
||||
const filter: Filter = {
|
||||
'#a': [identifier],
|
||||
authors: [pubkey],
|
||||
kinds: [kind]
|
||||
}
|
||||
|
||||
RelayController.getInstance()
|
||||
.fetchEvent(filter, relays)
|
||||
.then((event) => {
|
||||
if (event) {
|
||||
const extracted = extractModData(event)
|
||||
setMod(extracted)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
log(
|
||||
true,
|
||||
LogType.Error,
|
||||
'An error occurred in fetching mod details from relays',
|
||||
err
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
if (!mod) return <Spinner />
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='IBMSMSCWSPicWrapper'>
|
||||
<img
|
||||
src={mod.featuredImageUrl}
|
||||
onError={handleModImageError}
|
||||
className='IBMSMSCWSPic'
|
||||
/>
|
||||
</div>
|
||||
<div className='IBMSMSCWSInfo'>
|
||||
<h3 className='IBMSMSCWSInfoHeading'>{mod.title}</h3>
|
||||
<p className='IBMSMSCWSInfoText'>
|
||||
{mod.summary}
|
||||
<br />
|
||||
</p>
|
||||
<div className='IBMSMSliderContainerWrapperSliderAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMSliderContainerWrapperSliderActionbtn'
|
||||
role='button'
|
||||
onClick={() => navigate(getModsInnerPageRoute(naddr))}
|
||||
>
|
||||
Check it out
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
type DisplayModProps = {
|
||||
naddr: string
|
||||
}
|
||||
|
||||
const DisplayMod = ({ naddr }: DisplayModProps) => {
|
||||
const navigate = useNavigate()
|
||||
const [mod, setMod] = useState<ModDetails>()
|
||||
|
||||
useDidMount(() => {
|
||||
const decoded = nip19.decode<'naddr'>(naddr as `naddr1${string}`)
|
||||
const { identifier, kind, pubkey, relays = [] } = decoded.data
|
||||
|
||||
const filter: Filter = {
|
||||
'#a': [identifier],
|
||||
authors: [pubkey],
|
||||
kinds: [kind]
|
||||
}
|
||||
|
||||
RelayController.getInstance()
|
||||
.fetchEvent(filter, relays)
|
||||
.then((event) => {
|
||||
if (event) {
|
||||
const extracted = extractModData(event)
|
||||
setMod(extracted)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
log(
|
||||
true,
|
||||
LogType.Error,
|
||||
'An error occurred in fetching mod details from relays',
|
||||
err
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
if (!mod) return <Spinner />
|
||||
|
||||
const route = getModsInnerPageRoute(naddr)
|
||||
|
||||
return (
|
||||
<ModCard
|
||||
title={mod.title}
|
||||
summary={mod.summary}
|
||||
imageUrl={mod.featuredImageUrl}
|
||||
link={`#${route}`}
|
||||
handleClick={() => navigate(route)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const DisplayLatestMods = () => {
|
||||
const navigate = useNavigate()
|
||||
const [isFetchingLatestMods, setIsFetchingLatestMods] = useState(true)
|
||||
const [latestMods, setLatestMods] = useState<ModDetails[]>([])
|
||||
|
||||
useDidMount(() => {
|
||||
fetchMods({ source: window.location.host, limit: 4 })
|
||||
.then((res) => {
|
||||
setLatestMods(res)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsFetchingLatestMods(false)
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Latest Mods</h2>
|
||||
</div>
|
||||
<div className='IBMSMList'>
|
||||
{isFetchingLatestMods ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
latestMods.map((mod) => {
|
||||
const route = getModsInnerPageRoute(
|
||||
nip19.naddrEncode({
|
||||
identifier: mod.aTag,
|
||||
pubkey: mod.author,
|
||||
kind: kinds.ClassifiedListing
|
||||
})
|
||||
)
|
||||
|
||||
return (
|
||||
<ModCard
|
||||
key={mod.id}
|
||||
title={mod.title}
|
||||
summary={mod.summary}
|
||||
imageUrl={mod.featuredImageUrl}
|
||||
link={`#${route}`}
|
||||
handleClick={() => navigate(route)}
|
||||
/>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='IBMSMAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
onClick={() => navigate(appRoutes.mods)}
|
||||
>
|
||||
View All
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Spinner = () => {
|
||||
return (
|
||||
<div className='spinner'>
|
||||
<div className='spinnerCircle'></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ export const ModsPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
setIsFetching(true)
|
||||
fetchMods(filterOptions.source)
|
||||
fetchMods({ source: filterOptions.source })
|
||||
.then((res) => {
|
||||
setMods(res)
|
||||
})
|
||||
@ -106,7 +106,10 @@ export const ModsPage = () => {
|
||||
const until =
|
||||
mods.length > 0 ? mods[mods.length - 1].published_at - 1 : undefined
|
||||
|
||||
fetchMods(filterOptions.source, until)
|
||||
fetchMods({
|
||||
source: filterOptions.source,
|
||||
until
|
||||
})
|
||||
.then((res) => {
|
||||
setMods(res)
|
||||
setPage((prev) => prev + 1)
|
||||
@ -121,7 +124,10 @@ export const ModsPage = () => {
|
||||
|
||||
const since = mods.length > 0 ? mods[0].published_at + 1 : undefined
|
||||
|
||||
fetchMods(filterOptions.source, undefined, since)
|
||||
fetchMods({
|
||||
source: filterOptions.source,
|
||||
since
|
||||
})
|
||||
.then((res) => {
|
||||
setMods(res)
|
||||
setPage((prev) => prev - 1)
|
||||
@ -215,7 +221,7 @@ export const ModsPage = () => {
|
||||
key={mod.id}
|
||||
title={mod.title}
|
||||
summary={mod.summary}
|
||||
backgroundLink={mod.featuredImageUrl}
|
||||
imageUrl={mod.featuredImageUrl}
|
||||
link={`#${route}`}
|
||||
handleClick={() => navigate(route)}
|
||||
/>
|
||||
|
@ -1,6 +1,6 @@
|
||||
.swiper-pagination-bullet-active {
|
||||
background: rgba(255,255,255,0.5);
|
||||
box-shadow: 0 0 4px 0 rgba(0,0,0,0.5);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.simple-slider .swiper-slide {
|
||||
@ -22,16 +22,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.simple-slider .swiper-button-next, .simple-slider .swiper-button-prev {
|
||||
.simple-slider .swiper-button-next,
|
||||
.simple-slider .swiper-button-prev {
|
||||
width: 50px;
|
||||
margin-left: 00px;
|
||||
margin-right: 00px;
|
||||
color: rgba(255,255,255,0.5);
|
||||
background: linear-gradient(rgba(255,255,255,0.05), rgba(255,255,255,0.05)), linear-gradient(to top right, #262626, #292929, #262626), linear-gradient(to top right, #262626, #292929, #262626);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.05),
|
||||
rgba(255, 255, 255, 0.05)
|
||||
),
|
||||
linear-gradient(to top right, #262626, #292929, #262626),
|
||||
linear-gradient(to top right, #262626, #292929, #262626);
|
||||
padding: 10px;
|
||||
height: 75px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 8px 0 rgb(0,0,0,0.1);
|
||||
box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@ -39,19 +45,27 @@
|
||||
margin-top: -35px;
|
||||
}
|
||||
|
||||
.simple-slider .swiper-button-next:hover, .simple-slider .swiper-button-prev:hover {
|
||||
background: linear-gradient(rgba(255,255,255,0.1), rgba(255,255,255,0.1)), linear-gradient(to top right, #262626, #292929, #262626), linear-gradient(to top right, #262626, #292929, #262626);
|
||||
.simple-slider .swiper-button-next:hover,
|
||||
.simple-slider .swiper-button-prev:hover {
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.1),
|
||||
rgba(255, 255, 255, 0.1)
|
||||
),
|
||||
linear-gradient(to top right, #262626, #292929, #262626),
|
||||
linear-gradient(to top right, #262626, #292929, #262626);
|
||||
}
|
||||
|
||||
.swiper-button-next:after, .swiper-button-prev:after {
|
||||
font-size: 18px;
|
||||
.swiper-button-next:after,
|
||||
.swiper-button-prev:after {
|
||||
font-size: 18px!important;
|
||||
}
|
||||
|
||||
@media (max-width:992px) {
|
||||
.simple-slider .swiper-button-next, .simple-slider .swiper-button-prev {
|
||||
@media (max-width: 992px) {
|
||||
.simple-slider .swiper-button-next,
|
||||
.simple-slider .swiper-button-prev {
|
||||
bottom: 0;
|
||||
top: unset;
|
||||
width: 48%;
|
||||
width: 45%;
|
||||
height: unset;
|
||||
padding: 10px;
|
||||
}
|
||||
@ -115,7 +129,12 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background: linear-gradient(rgba(255,255,255,0.15), rgba(255,255,255,0.15)), linear-gradient(to top right, #262626, #292929, #262626), linear-gradient(to top right, #262626, #292929, #262626);
|
||||
background: linear-gradient(
|
||||
rgba(255, 255, 255, 0.15),
|
||||
rgba(255, 255, 255, 0.15)
|
||||
),
|
||||
linear-gradient(to top right, #262626, #292929, #262626),
|
||||
linear-gradient(to top right, #262626, #292929, #262626);
|
||||
z-index: -1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
@ -129,12 +148,15 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets, .swiper-pagination-custom, .swiper-pagination-fraction {
|
||||
.swiper-container-horizontal > .swiper-pagination-bullets,
|
||||
.swiper-pagination-custom,
|
||||
.swiper-pagination-fraction {
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.swiper-button-next, .swiper-button-prev {
|
||||
.swiper-button-next,
|
||||
.swiper-button-prev {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
@ -161,23 +183,35 @@
|
||||
.SliderWrapper {
|
||||
width: 100%;
|
||||
padding: 50px 0;
|
||||
background: rgba(0,0,0,0.1);
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: -25px 0 0 0;
|
||||
border-bottom: solid 1px rgba(255,255,255,0.05);
|
||||
border-bottom: solid 1px rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.IBMSMSCWSPic {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
border: solid 1px rgba(255,255,255,0.05);
|
||||
padding-top: 50%;
|
||||
border: solid 1px rgba(255, 255, 255, 0.05);
|
||||
z-index: 1;
|
||||
box-shadow: 0 0 8px 0 rgba(0,0,0,0.25);
|
||||
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* Ensures the image covers the container like a background image */
|
||||
}
|
||||
|
||||
.IBMSMSCWSPicWrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.IBMSMSCWSInfo {
|
||||
@ -187,9 +221,15 @@
|
||||
justify-content: center;
|
||||
padding: 25px;
|
||||
border-radius: 10px;
|
||||
background: linear-gradient(rgba(255,255,255,0), rgba(255,255,255,0)), linear-gradient(to top right, rgb(38,38,38), rgb(41,41,41), rgb(38,38,38));
|
||||
box-shadow: 0 0 8px 0 rgb(0,0,0,0.1);
|
||||
border: solid 1px rgba(255,255,255,0.05);
|
||||
background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0)),
|
||||
linear-gradient(
|
||||
to top right,
|
||||
rgb(38, 38, 38),
|
||||
rgb(41, 41, 41),
|
||||
rgb(38, 38, 38)
|
||||
);
|
||||
box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1);
|
||||
border: solid 1px rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@ -212,7 +252,7 @@
|
||||
-webkit-line-clamp: 2;
|
||||
font-size: 20px;
|
||||
line-height: 1.25;
|
||||
color: rgba(255,255,255,0.75);
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@ -221,7 +261,7 @@
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 8;
|
||||
color: rgba(255,255,255,0.5);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
flex-grow: 1;
|
||||
@ -235,6 +275,8 @@
|
||||
}
|
||||
|
||||
.swiper-pagination {
|
||||
display: none;
|
||||
bottom: -10px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
@ -244,7 +286,7 @@
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet {
|
||||
background: rgba(0,0,0,0.5);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
opacity: 1;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
@ -252,6 +294,5 @@
|
||||
}
|
||||
|
||||
.swiper-pagination-bullet.swiper-pagination-bullet-active {
|
||||
background: rgba(128,0,255,0.5);
|
||||
background: rgba(128, 0, 255, 0.5);
|
||||
}
|
||||
|
||||
|
@ -17,16 +17,24 @@
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.cardGameMain {
|
||||
.cardGameMainWrapper {
|
||||
position: relative;
|
||||
padding-top: 150%;
|
||||
}
|
||||
|
||||
.cardGameMain {
|
||||
border-radius: 15px;
|
||||
background: rgba(255,255,255,0.05);
|
||||
box-shadow: 0 0 8px 0 rgb(0,0,0,0.1);
|
||||
box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
object-fit: cover; /* Ensures the image covers the container like a background image */
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.cardGameMainTitle {
|
||||
transition: ease 0.4s;
|
||||
color: rgba(255,255,255,0.5);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
padding: 0 15px;
|
||||
font-weight: bold;
|
||||
display: -webkit-box;
|
||||
@ -36,4 +44,3 @@
|
||||
font-size: 18px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,18 @@
|
||||
background: linear-gradient(to top right, #262626, #292929, #262626);
|
||||
}
|
||||
|
||||
.cMMPicture {
|
||||
.cMMPictureWrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-top: 56.25%;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.cMMPicture {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
object-fit: cover; /* Ensures the image covers the container like a background image */
|
||||
}
|
||||
|
||||
.cMMBody {
|
||||
|
@ -655,3 +655,28 @@ a:hover {
|
||||
|
||||
.errorMainText {
|
||||
}
|
||||
|
||||
.spinner {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.spinnerCircle {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #3498db;
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
text-decoration: unset;
|
||||
}
|
||||
|
||||
.IBMSMSMBSSTagsTag:active {
|
||||
|
@ -134,6 +134,13 @@ export const initializeFormState = (
|
||||
]
|
||||
})
|
||||
|
||||
interface FetchModsOptions {
|
||||
source?: string
|
||||
until?: number
|
||||
since?: number
|
||||
limit?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of mods based on the provided source.
|
||||
*
|
||||
@ -144,15 +151,16 @@ export const initializeFormState = (
|
||||
* @returns A promise that resolves to an array of `ModDetails` objects. In case of an error,
|
||||
* it logs the error and shows a notification, then returns an empty array.
|
||||
*/
|
||||
export const fetchMods = async (
|
||||
source: string,
|
||||
until?: number,
|
||||
since?: number
|
||||
): Promise<ModDetails[]> => {
|
||||
export const fetchMods = async ({
|
||||
source,
|
||||
until,
|
||||
since,
|
||||
limit
|
||||
}: FetchModsOptions): Promise<ModDetails[]> => {
|
||||
// Define the filter criteria for fetching mods
|
||||
const filter: Filter = {
|
||||
kinds: [kinds.ClassifiedListing], // Specify the kind of events to fetch
|
||||
limit: MOD_FILTER_LIMIT, // Limit the number of events fetched to 20
|
||||
limit: limit || MOD_FILTER_LIMIT, // Limit the number of events fetched to 20
|
||||
'#t': [T_TAG_VALUE],
|
||||
until, // Optional filter to fetch events until this timestamp
|
||||
since // Optional filter to fetch events from this timestamp
|
||||
|
@ -123,3 +123,15 @@ export const abbreviateNumber = (value: number): string => {
|
||||
return value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export const handleGameImageError = (
|
||||
e: React.SyntheticEvent<HTMLImageElement, Event>
|
||||
) => {
|
||||
e.currentTarget.src = import.meta.env.VITE_FALLBACK_GAME_IMAGE
|
||||
}
|
||||
|
||||
export const handleModImageError = (
|
||||
e: React.SyntheticEvent<HTMLImageElement, Event>
|
||||
) => {
|
||||
e.currentTarget.src = import.meta.env.VITE_FALLBACK_MOD_IMAGE
|
||||
}
|
||||
|
2
src/vite-env.d.ts
vendored
2
src/vite-env.d.ts
vendored
@ -4,6 +4,8 @@ interface ImportMetaEnv {
|
||||
readonly VITE_APP_RELAY: string
|
||||
readonly VITE_ADMIN_NPUBS: string
|
||||
readonly VITE_REPORTING_NPUB: string
|
||||
readonly VITE_FALLBACK_MOD_IMAGE: string
|
||||
readonly VITE_FALLBACK_GAME_IMAGE: string
|
||||
// more env variables...
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user