feat: blogs #118
@ -20,7 +20,8 @@ export const LANDING_PAGE_DATA = {
|
||||
'Cyberpunk 2077',
|
||||
'ELDEN RING',
|
||||
'The Coffin of Andy and Leyley'
|
||||
]
|
||||
],
|
||||
featuredBlogPosts: []
|
||||
}
|
||||
// we use this object to check if a user has reacted positively or negatively to a post
|
||||
// reactions are kind 7 events and their content is either emoji icon or emoji shortcode
|
||||
|
@ -17,11 +17,11 @@ export const blogRouteLoader =
|
||||
|
||||
try {
|
||||
const filter = filterForEventsTaggingId(naddr)
|
||||
|
||||
if (!filter) {
|
||||
log(true, LogType.Error, 'Unable to create filter from blog naddr.')
|
||||
return redirect(appRoutes.blogs)
|
||||
}
|
||||
|
||||
const event = await ndkContext.fetchEvent(filter)
|
||||
if (!event) {
|
||||
log(true, LogType.Error, 'Unable to fetch the blog event.')
|
||||
@ -29,7 +29,6 @@ export const blogRouteLoader =
|
||||
}
|
||||
|
||||
const blogDetails = extractBlogDetails(event)
|
||||
|
||||
return blogDetails
|
||||
} catch (error) {
|
||||
log(
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { NDKFilter } from '@nostr-dev-kit/ndk'
|
||||
import { NDKContextType } from 'contexts/NDKContext'
|
||||
import { kinds } from 'nostr-tools'
|
||||
import { toast } from 'react-toastify'
|
||||
import { log, LogType, npubToHex } from 'utils'
|
||||
import { extractBlogCardDetails } from 'utils/blog'
|
||||
|
||||
@ -31,7 +30,6 @@ export const blogsRouteLoader = (ndkContext: NDKContextType) => async () => {
|
||||
'An error occurred in fetching blog details from relays',
|
||||
error
|
||||
)
|
||||
toast.error('An error occurred in fetching blog details from relays')
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { kinds, nip19 } from 'nostr-tools'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import { A11y, Autoplay, Navigation, Pagination } from 'swiper/modules'
|
||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||
import { BlogCard } from '../components/BlogCard'
|
||||
@ -15,19 +15,25 @@ import {
|
||||
useNSFWList
|
||||
} from '../hooks'
|
||||
import { appRoutes, getModPageRoute } from '../routes'
|
||||
import { ModDetails } from '../types'
|
||||
import { extractModData, handleModImageError, log, LogType } from '../utils'
|
||||
import { BlogCardDetails, ModDetails } from '../types'
|
||||
import {
|
||||
extractModData,
|
||||
handleModImageError,
|
||||
log,
|
||||
LogType,
|
||||
npubToHex
|
||||
} from '../utils'
|
||||
|
||||
import '../styles/cardLists.css'
|
||||
import '../styles/SimpleSlider.css'
|
||||
import '../styles/styles.css'
|
||||
|
||||
// Import Swiper styles
|
||||
import { NDKFilter } from '@nostr-dev-kit/ndk'
|
||||
import { filterForEventsTaggingId, NDKFilter } from '@nostr-dev-kit/ndk'
|
||||
import 'swiper/css'
|
||||
import 'swiper/css/navigation'
|
||||
import 'swiper/css/pagination'
|
||||
import placeholder from '../assets/img/DEGMods Placeholder Img.png'
|
||||
import { extractBlogCardDetails } from 'utils/blog'
|
||||
|
||||
export const HomePage = () => {
|
||||
const navigate = useNavigate()
|
||||
@ -114,27 +120,7 @@ export const HomePage = () => {
|
||||
</div>
|
||||
</div>
|
||||
<DisplayLatestMods />
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Blog Posts (WIP)</h2>
|
||||
</div>
|
||||
<div className='IBMSMList'>
|
||||
<BlogCard image={placeholder} />
|
||||
<BlogCard image={placeholder} />
|
||||
<BlogCard image={placeholder} />
|
||||
<BlogCard image={placeholder} />
|
||||
</div>
|
||||
|
||||
<div className='IBMSMAction'>
|
||||
<a
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
href='blog.html'
|
||||
>
|
||||
View All
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<DisplayLatestBlogs />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -327,3 +313,105 @@ const Spinner = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const DisplayLatestBlogs = () => {
|
||||
const [blogs, setBlogs] = useState<Partial<BlogCardDetails>[]>()
|
||||
const { fetchEvents } = useNDKContext()
|
||||
|
||||
useDidMount(() => {
|
||||
const fetchBlogs = async () => {
|
||||
try {
|
||||
// Show maximum of 4 blog posts
|
||||
// 2 should be featured and the most recent 2 from blog npubs
|
||||
|
||||
// Populate the filter from known naddr (constants.ts)
|
||||
const filters: NDKFilter[] = []
|
||||
for (let i = 0; i < LANDING_PAGE_DATA.featuredBlogPosts.length; i++) {
|
||||
try {
|
||||
const naddr = LANDING_PAGE_DATA.featuredBlogPosts[i]
|
||||
const filterId = filterForEventsTaggingId(naddr)
|
||||
if (filterId) {
|
||||
filters.push(filterId)
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently ignore
|
||||
}
|
||||
}
|
||||
// Create a single filter based on multiple #a's
|
||||
const filter = filters.reduce(
|
||||
(filter, id) => {
|
||||
const a = id['#a']
|
||||
if (a) {
|
||||
filter['#a']?.push(a[0])
|
||||
}
|
||||
return filter
|
||||
},
|
||||
{
|
||||
'#a': []
|
||||
} as NDKFilter
|
||||
)
|
||||
// Fetch featured blogs posts
|
||||
const featuredBlogPosts = await fetchEvents(filter)
|
||||
|
||||
// Fetch latest blog npubs posts
|
||||
const blogNpubs = import.meta.env.VITE_BLOG_NPUBS.split(',')
|
||||
const blogHexkeys = blogNpubs
|
||||
.map(npubToHex)
|
||||
.filter((hexkey) => hexkey !== null)
|
||||
|
||||
// We fetch 4 posts in case of duplicates (from featured)
|
||||
const latestBlogPosts = await fetchEvents({
|
||||
authors: blogHexkeys,
|
||||
kinds: [kinds.LongFormArticle],
|
||||
limit: 4
|
||||
})
|
||||
|
||||
// Remove duplicates
|
||||
const unique = Array.from(
|
||||
[...featuredBlogPosts, ...latestBlogPosts]
|
||||
.reduce((map, obj) => {
|
||||
map.set(obj.id, obj)
|
||||
return map
|
||||
}, new Map())
|
||||
.values()
|
||||
)
|
||||
const latest = unique.slice(0, 4)
|
||||
|
||||
setBlogs(latest.map(extractBlogCardDetails))
|
||||
} catch (error) {
|
||||
log(
|
||||
true,
|
||||
LogType.Error,
|
||||
'An error occurred in fetching blog details from relays',
|
||||
error
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fetchBlogs()
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='IBMSecMain IBMSMListWrapper'>
|
||||
<div className='IBMSMTitleMain'>
|
||||
<h2 className='IBMSMTitleMainHeading'>Blog Posts</h2>
|
||||
</div>
|
||||
<div className='IBMSMList'>
|
||||
{blogs?.map((b) => (
|
||||
<BlogCard key={b.id} {...b} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className='IBMSMAction'>
|
||||
<Link
|
||||
className='btn btnMain IBMSMActionBtn'
|
||||
role='button'
|
||||
to={appRoutes.blogs}
|
||||
>
|
||||
View All
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user