From faf30a89b01e8a0133569f41833bafeb5361bc0a Mon Sep 17 00:00:00 2001 From: freakoverse Date: Sat, 31 Aug 2024 12:03:57 +0000 Subject: [PATCH 01/16] Update src/styles/tags.css --- src/styles/tags.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/tags.css b/src/styles/tags.css index 9a94e80..bbcd86a 100644 --- a/src/styles/tags.css +++ b/src/styles/tags.css @@ -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 { From 0733849b25b78d92ddb771bb529ee604f4c1c931 Mon Sep 17 00:00:00 2001 From: daniyal Date: Mon, 2 Sep 2024 13:43:39 +0500 Subject: [PATCH 02/16] chore: use fallback images for mod and games if provided image gives error --- .env.example | 8 ++- .gitea/workflows/release-production.yaml | 2 + .gitea/workflows/release-staging.yaml | 2 + src/components/GameCard.tsx | 17 ++--- src/components/ModCard.tsx | 14 ++-- src/styles/SimpleSlider.css | 82 ++++++++++++++++-------- src/styles/cardGames.css | 9 ++- src/styles/cardMod.css | 4 +- src/utils/utils.ts | 12 ++++ src/vite-env.d.ts | 2 + 10 files changed, 102 insertions(+), 50 deletions(-) diff --git a/.env.example b/.env.example index 6404610..e6b55e6 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,10 @@ VITE_APP_RELAY=wss://relay.degmods.com VITE_ADMIN_NPUBS= # A dedicated npub used for reporting mods, blogs, profile and etc. -VITE_REPORTING_NPUB= \ No newline at end of file +VITE_REPORTING_NPUB= + +# 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 \ No newline at end of file diff --git a/.gitea/workflows/release-production.yaml b/.gitea/workflows/release-production.yaml index 1415a50..88cffa7 100644 --- a/.gitea/workflows/release-production.yaml +++ b/.gitea/workflows/release-production.yaml @@ -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 diff --git a/.gitea/workflows/release-staging.yaml b/.gitea/workflows/release-staging.yaml index c08b4e8..10e4bc4 100644 --- a/.gitea/workflows/release-staging.yaml +++ b/.gitea/workflows/release-staging.yaml @@ -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 diff --git a/src/components/GameCard.tsx b/src/components/GameCard.tsx index 9cd2c03..425d3b9 100644 --- a/src/components/GameCard.tsx +++ b/src/components/GameCard.tsx @@ -1,20 +1,21 @@ 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 ( -
+ />
-

This is a game title, the best game title

+

{title}

) diff --git a/src/components/ModCard.tsx b/src/components/ModCard.tsx index a47c927..398f04c 100644 --- a/src/components/ModCard.tsx +++ b/src/components/ModCard.tsx @@ -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,11 @@ export const ModCard = ({ }} >
-
+ />

{title}

{summary}

diff --git a/src/styles/SimpleSlider.css b/src/styles/SimpleSlider.css index 9ea9e1a..1188b20 100644 --- a/src/styles/SimpleSlider.css +++ b/src/styles/SimpleSlider.css @@ -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,16 +45,24 @@ 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 { +.swiper-button-next:after, +.swiper-button-prev:after { font-size: 18px; } -@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%; @@ -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,24 @@ .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%; + object-fit: cover; /* Ensures the image covers the container like a background image */ } .IBMSMSCWSInfo { @@ -187,9 +210,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 +241,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 +250,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; @@ -244,7 +273,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 +281,5 @@ } .swiper-pagination-bullet.swiper-pagination-bullet-active { - background: rgba(128,0,255,0.5); + background: rgba(128, 0, 255, 0.5); } - diff --git a/src/styles/cardGames.css b/src/styles/cardGames.css index 4aee260..b4028e4 100644 --- a/src/styles/cardGames.css +++ b/src/styles/cardGames.css @@ -18,15 +18,15 @@ } .cardGameMain { - padding-top: 150%; 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 */ } .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 +36,3 @@ font-size: 18px; line-height: 1.5; } - diff --git a/src/styles/cardMod.css b/src/styles/cardMod.css index ec7b3ae..7499467 100644 --- a/src/styles/cardMod.css +++ b/src/styles/cardMod.css @@ -12,8 +12,8 @@ .cMMPicture { position: relative; width: 100%; - padding-top: 56.25%; - background: rgba(0, 0, 0, 0.1); + width: 100%; + object-fit: cover; /* Ensures the image covers the container like a background image */ } .cMMBody { diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 85dabeb..b321c91 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -123,3 +123,15 @@ export const abbreviateNumber = (value: number): string => { return value.toString() } } + +export const handleGameImageError = ( + e: React.SyntheticEvent +) => { + e.currentTarget.src = import.meta.env.VITE_FALLBACK_GAME_IMAGE +} + +export const handleModImageError = ( + e: React.SyntheticEvent +) => { + e.currentTarget.src = import.meta.env.VITE_FALLBACK_MOD_IMAGE +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 141f56d..1f3c47c 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -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... } From c6831f3fb26494fc1eedf79de411104a5b9342bd Mon Sep 17 00:00:00 2001 From: daniyal Date: Mon, 2 Sep 2024 13:44:58 +0500 Subject: [PATCH 03/16] chore: add a map in relay controller for storing events --- src/controllers/relay.ts | 46 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/controllers/relay.ts b/src/controllers/relay.ts index f688878..2e362ca 100644 --- a/src/controllers/relay.ts +++ b/src/controllers/relay.ts @@ -14,6 +14,7 @@ import { MetadataController, UserRelaysType } from './metadata' */ export class RelayController { private static instance: RelayController + private events = new Map() 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 => { + // 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() From 56ec37e57ba3566fda7ff41dea7262d8543d86ce Mon Sep 17 00:00:00 2001 From: daniyal Date: Mon, 2 Sep 2024 13:47:16 +0500 Subject: [PATCH 04/16] feat: display data on landing page --- index.html | 26 ++- package-lock.json | 19 ++ package.json | 1 + src/constants.ts | 35 ++++ src/pages/games.tsx | 25 ++- src/pages/home.tsx | 445 ++++++++++++++++++++++-------------------- src/pages/mods.tsx | 14 +- src/styles/styles.css | 25 +++ src/utils/mod.ts | 20 +- 9 files changed, 379 insertions(+), 231 deletions(-) diff --git a/index.html b/index.html index fef57eb..5d13bc4 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,10 @@ - + @@ -14,24 +17,33 @@ - + - + - - + DEG Mods - Liberating Game Mods
- - + diff --git a/package-lock.json b/package-lock.json index 3d378b3..6526152 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index f4cec95..7fd0014 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/constants.ts b/src/constants.ts index d141103..2cba654 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,2 +1,37 @@ export const T_TAG_VALUE = 'GameMod' export const MOD_FILTER_LIMIT = 20 +export const LANDING_PAGE_DATA = { + featuredSlider: [ + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5d3excenzvf5xgkkvdny8qkngveex5knjcnxxqkn2efnx3jrxvpcxgukxdggsmal6', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5df5xccngvtrxqkkydpexukngvp4xgknsvp4vskkgdrxvgmkxdmp8quxycgx78rpf', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vf5x9nrxcekxvknjvmzxvkngcfsx5kkzcf3xqknsvmrvgenwe3j8p3nzwgka59vj' + ], + awesomeMods: [ + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5d3excenzvf5xgkkvdny8qkngveex5knjcnxxqkn2efnx3jrxvpcxgukxdggsmal6', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5df5xccngvtrxqkkydpexukngvp4xgknsvp4vskkgdrxvgmkxdmp8quxycgx78rpf', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx' + ], + featuredGames: [ + { + title: 'Immortal Guns', + imageUrl: '' + }, + { + title: 'The Bounce House', + imageUrl: '' + }, + { + title: 'Immortal Guns', + imageUrl: '' + }, + { + title: 'Magenta Horizon Act 1', + imageUrl: '' + }, + { + title: 'DEAD LETTER DEPT. Demo', + imageUrl: '' + } + ] +} diff --git a/src/pages/games.tsx b/src/pages/games.tsx index bdd5dc9..d2ed7bc 100644 --- a/src/pages/games.tsx +++ b/src/pages/games.tsx @@ -35,11 +35,26 @@ export const GamesPage = () => {
- - - - - + + + + +
diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 9a9cef3..b570374 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -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 (
-
-
-
-
-
-

Placeholder

-

- 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. -
-

- -
-
-
-
-
-

Placeholder

-

- 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. -
-

- -
-
-
-
-
-

Placeholder

-

- 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. -
-

- -
-
-
-
-
-
-
+ + {LANDING_PAGE_DATA.featuredSlider.map((naddr) => ( + + + + ))} +
@@ -126,20 +61,18 @@ export const HomePage = () => {
-

Cool Games (WIP)

+

Cool Games

- - - - - + {LANDING_PAGE_DATA.featuredGames.map((game) => ( + + ))}
navigate(appRoutes.games)} > View All @@ -147,114 +80,24 @@ export const HomePage = () => {
-

Awesome Mods (WIP)

+

Awesome Mods

- { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> - { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> - { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> + {LANDING_PAGE_DATA.awesomeMods.map((naddr) => ( + + ))}
-
-
-
-

Latest Mods (WIP)

-
-
- { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> - { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> - { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> - { - alert( - 'these are dummy mods. So navigation on these are not implemented yet' - ) - }} - /> -
- -
+

Blog Posts (WIP)

@@ -281,3 +124,187 @@ export const HomePage = () => {
) } + +type SlideContentProps = { + naddr: string +} + +const SlideContent = ({ naddr }: SlideContentProps) => { + const navigate = useNavigate() + const [mod, setMod] = useState() + + 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 + + return ( + <> + +
+

{mod.title}

+

+ {mod.summary} +
+

+ +
+ + ) +} + +type DisplayModProps = { + naddr: string +} + +const DisplayMod = ({ naddr }: DisplayModProps) => { + const navigate = useNavigate() + const [mod, setMod] = useState() + + 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 + + const route = getModsInnerPageRoute(naddr) + + return ( + navigate(route)} + /> + ) +} + +const DisplayLatestMods = () => { + const navigate = useNavigate() + const [isFetchingLatestMods, setIsFetchingLatestMods] = useState(true) + const [latestMods, setLatestMods] = useState([]) + + useDidMount(() => { + fetchMods({ source: window.location.host, limit: 4 }) + .then((res) => { + setLatestMods(res) + }) + .finally(() => { + setIsFetchingLatestMods(false) + }) + }) + + return ( +
+
+

Latest Mods

+
+
+ {isFetchingLatestMods ? ( + + ) : ( + latestMods.map((mod) => { + const route = getModsInnerPageRoute( + nip19.naddrEncode({ + identifier: mod.aTag, + pubkey: mod.author, + kind: kinds.ClassifiedListing + }) + ) + + return ( + navigate(route)} + /> + ) + }) + )} +
+ + +
+ ) +} + +const Spinner = () => { + return ( +
+
+
+ ) +} diff --git a/src/pages/mods.tsx b/src/pages/mods.tsx index e61be15..0c3506c 100644 --- a/src/pages/mods.tsx +++ b/src/pages/mods.tsx @@ -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)} /> diff --git a/src/styles/styles.css b/src/styles/styles.css index 6c11cf6..d9a719f 100644 --- a/src/styles/styles.css +++ b/src/styles/styles.css @@ -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); + } +} diff --git a/src/utils/mod.ts b/src/utils/mod.ts index ac2a9cc..6e3511d 100644 --- a/src/utils/mod.ts +++ b/src/utils/mod.ts @@ -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 => { +export const fetchMods = async ({ + source, + until, + since, + limit +}: FetchModsOptions): Promise => { // 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 From 098068acef4eab9d3073b07b65fcacf77af17f1f Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:03:41 +0000 Subject: [PATCH 05/16] div wrapped the slider image --- src/pages/home.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/home.tsx b/src/pages/home.tsx index b570374..f34ad81 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -165,11 +165,13 @@ const SlideContent = ({ naddr }: SlideContentProps) => { return ( <> - +
+ +

{mod.title}

From 41240ee3fbc8a02a1056939b4528953988492b8a Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:04:57 +0000 Subject: [PATCH 06/16] Update src/styles/SimpleSlider.css --- src/styles/SimpleSlider.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/styles/SimpleSlider.css b/src/styles/SimpleSlider.css index 1188b20..e9c69ae 100644 --- a/src/styles/SimpleSlider.css +++ b/src/styles/SimpleSlider.css @@ -200,9 +200,20 @@ z-index: 1; 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 { display: flex; flex-direction: column; From 24ea309dd1890ec8086c429034871380cad468b5 Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:27:23 +0000 Subject: [PATCH 07/16] Update src/styles/SimpleSlider.css --- src/styles/SimpleSlider.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/styles/SimpleSlider.css b/src/styles/SimpleSlider.css index e9c69ae..60bf918 100644 --- a/src/styles/SimpleSlider.css +++ b/src/styles/SimpleSlider.css @@ -57,7 +57,7 @@ .swiper-button-next:after, .swiper-button-prev:after { - font-size: 18px; + font-size: 18px!important; } @media (max-width: 992px) { @@ -65,7 +65,7 @@ .simple-slider .swiper-button-prev { bottom: 0; top: unset; - width: 48%; + width: 45%; height: unset; padding: 10px; } @@ -275,6 +275,8 @@ } .swiper-pagination { + display: none; + bottom: -10px !important; } @media (max-width: 992px) { From 16b3c7684b52c583259e47115467a54b6c4ecf80 Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:38:43 +0000 Subject: [PATCH 08/16] Update src/styles/cardGames.css --- src/styles/cardGames.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/styles/cardGames.css b/src/styles/cardGames.css index b4028e4..1f31c95 100644 --- a/src/styles/cardGames.css +++ b/src/styles/cardGames.css @@ -22,6 +22,8 @@ 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 */ + height: 396px; + max-width: 264px; } .cardGameMainTitle { From 9a192451f6a6c3a7b0cd2da203033492ecc2f9ca Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:47:55 +0000 Subject: [PATCH 09/16] Update src/styles/cardGames.css --- src/styles/cardGames.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/styles/cardGames.css b/src/styles/cardGames.css index 1f31c95..1e6aadd 100644 --- a/src/styles/cardGames.css +++ b/src/styles/cardGames.css @@ -17,13 +17,19 @@ transform: scale(1); } +.cardGameMainWrapper { + position: relative; + padding-top: 150%; +} + .cardGameMain { border-radius: 15px; 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 */ - height: 396px; - max-width: 264px; + position: absolute; + height: 100%; + top: 0; } .cardGameMainTitle { From 1b2926ae77983e9533c4e66b632189152f5a2965 Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:48:51 +0000 Subject: [PATCH 10/16] Update src/components/GameCard.tsx --- src/components/GameCard.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/GameCard.tsx b/src/components/GameCard.tsx index 425d3b9..e7102a6 100644 --- a/src/components/GameCard.tsx +++ b/src/components/GameCard.tsx @@ -9,11 +9,13 @@ type GameCardProps = { export const GameCard = ({ title, imageUrl }: GameCardProps) => { return ( - +

{title}

From 764c936ff8939b6bbf0e89cb25d054953f419d0a Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:49:53 +0000 Subject: [PATCH 11/16] Update src/components/GameCard.tsx --- src/components/GameCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/GameCard.tsx b/src/components/GameCard.tsx index e7102a6..ade5f15 100644 --- a/src/components/GameCard.tsx +++ b/src/components/GameCard.tsx @@ -9,7 +9,7 @@ type GameCardProps = { export const GameCard = ({ title, imageUrl }: GameCardProps) => { return (
-
Date: Mon, 2 Sep 2024 09:53:22 +0000 Subject: [PATCH 12/16] wrapped the mod image with a div to fix its presentation --- src/components/ModCard.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/ModCard.tsx b/src/components/ModCard.tsx index 398f04c..86b7070 100644 --- a/src/components/ModCard.tsx +++ b/src/components/ModCard.tsx @@ -26,11 +26,13 @@ export const ModCard = ({ }} >
- +
+ +

{title}

{summary}

From 8726d042f268d3bfd5962da162185690440a937e Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:55:00 +0000 Subject: [PATCH 13/16] Update src/styles/cardMod.css --- src/styles/cardMod.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/styles/cardMod.css b/src/styles/cardMod.css index 7499467..f50658c 100644 --- a/src/styles/cardMod.css +++ b/src/styles/cardMod.css @@ -9,10 +9,16 @@ background: linear-gradient(to top right, #262626, #292929, #262626); } -.cMMPicture { +.cMMPictureWrapper { position: relative; width: 100%; + padding-top: 56.25%; +} + +.cMMPicture { + position: absolute; width: 100%; + height: 100%; object-fit: cover; /* Ensures the image covers the container like a background image */ } From f13d800d85f8dcbe445e2b2af3f12776c25d6ddc Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 09:57:28 +0000 Subject: [PATCH 14/16] Update src/styles/cardMod.css --- src/styles/cardMod.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/cardMod.css b/src/styles/cardMod.css index f50658c..4bd8600 100644 --- a/src/styles/cardMod.css +++ b/src/styles/cardMod.css @@ -19,6 +19,7 @@ position: absolute; width: 100%; height: 100%; + top: 0; object-fit: cover; /* Ensures the image covers the container like a background image */ } From b492f977951980d6c21c7e89145c50948ad349fb Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 10:01:30 +0000 Subject: [PATCH 15/16] Update src/constants.ts --- src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.ts b/src/constants.ts index 2cba654..2db8cd9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -14,7 +14,7 @@ export const LANDING_PAGE_DATA = { ], featuredGames: [ { - title: 'Immortal Guns', + title: 'SUPERHOT', imageUrl: '' }, { From b4465ee1c6c511b33389a34ebabb3ac1680eef5d Mon Sep 17 00:00:00 2001 From: freakoverse Date: Mon, 2 Sep 2024 10:23:13 +0000 Subject: [PATCH 16/16] Update src/constants.ts --- src/constants.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 2db8cd9..f0e7bff 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,9 +2,10 @@ export const T_TAG_VALUE = 'GameMod' export const MOD_FILTER_LIMIT = 20 export const LANDING_PAGE_DATA = { featuredSlider: [ + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5cek8pnrwc34xgknyv33xqkngc34xyknscfjxsknzvp38quxgc33vejnqvqhqecq8', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vpcxs6nwwp3x5knyd3evckngetxxcknjdfkx5kngdfhvgukvwfjxsunseqnend73', 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5d3excenzvf5xgkkvdny8qkngveex5knjcnxxqkn2efnx3jrxvpcxgukxdggsmal6', - 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5df5xccngvtrxqkkydpexukngvp4xgknsvp4vskkgdrxvgmkxdmp8quxycgx78rpf', - 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vrrvgmnjc33xuknwde4vskngvekxgknsenyxvkk2ctxvscrvenpvsmnxeqydygjx', + 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5dp4xsex2e3cxuknsdryvvkngc3sxcknjef4vcknvvmyvcukyd3kvd3rxdgnuver5', 'naddr1qvzqqqrkcgpzquuz5nxzzap2c034s8cuv5ayr7gjaxz7d22pgwfh0qpmsesy9eflqp4nxvp5xqer5den8qexzdrrvverzde5xfskxvm9xv6nsvtxx93nvdfnvy6rze3exyex2wfcx4jnvcfexscngveexvmnwwpsxd3rsd3kxq6ryef4xdnr5vf5x9nrxcekxvknjvmzxvkngcfsx5kkzcf3xqknsvmrvgenwe3j8p3nzwgka59vj' ], awesomeMods: [