feat: home tag page
This commit is contained in:
parent
f138acc154
commit
46969f85cb
|
|
@ -0,0 +1,39 @@
|
|||
import { Metadata } from "next"
|
||||
|
||||
import { HomeFeed } from "~/components/home/HomeFeed"
|
||||
import { HomeSidebar } from "~/components/home/HomeSidebar"
|
||||
import { APP_NAME } from "~/lib/env"
|
||||
|
||||
export function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: {
|
||||
tag: string
|
||||
}
|
||||
}): Metadata {
|
||||
return {
|
||||
title: `Tag: ${params.tag} - ${APP_NAME}`,
|
||||
}
|
||||
}
|
||||
|
||||
export default function Tag({
|
||||
params,
|
||||
}: {
|
||||
params: {
|
||||
tag: string
|
||||
}
|
||||
}) {
|
||||
params.tag = decodeURIComponent(params.tag)
|
||||
|
||||
return (
|
||||
<section className="pt-24">
|
||||
<div className="max-w-screen-lg px-5 mx-auto flex">
|
||||
<div className="flex-1 min-w-[300px]">
|
||||
<h2 className="text-3xl font-bold">Tag: {params.tag}</h2>
|
||||
<HomeFeed type="tag" />
|
||||
</div>
|
||||
<HomeSidebar />
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
@ -31,11 +31,9 @@ function Topic({
|
|||
<section className="pt-24">
|
||||
<div className="max-w-screen-lg px-5 mx-auto flex">
|
||||
<div className="flex-1 min-w-[300px]">
|
||||
<h2 className="text-3xl font-bold">Topic: {params.topic}</h2>
|
||||
<p className="text-zinc-400 mt-4">{info?.description}</p>
|
||||
<div className="mt-10">
|
||||
<HomeFeed type="topic" noteIds={info?.notes} />
|
||||
</div>
|
||||
<h2 className="text-4xl font-bold mb-4">Topic: {params.topic}</h2>
|
||||
<p className="text-zinc-400 mb-6">{info?.description}</p>
|
||||
<HomeFeed type="topic" noteIds={info?.notes} />
|
||||
</div>
|
||||
<HomeSidebar />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import { useRouter, useSearchParams } from "next/navigation"
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation"
|
||||
import { memo, useEffect, useState } from "react"
|
||||
import reactStringReplace from "react-string-replace"
|
||||
import { Virtuoso } from "react-virtuoso"
|
||||
|
|
@ -46,7 +46,7 @@ const Post = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<CharacterFloatCard siteId={post.character?.handle}>
|
||||
<Link
|
||||
|
|
@ -172,6 +172,8 @@ export const HomeFeed: React.FC<{
|
|||
const [hotInterval, setHotInterval] = useState(7)
|
||||
const [searchType, setSearchType] = useState<SearchType>("latest")
|
||||
|
||||
const params = useParams()
|
||||
|
||||
const feed = useGetFeed({
|
||||
type: feedType,
|
||||
characterId: currentCharacterId,
|
||||
|
|
@ -179,6 +181,7 @@ export const HomeFeed: React.FC<{
|
|||
daysInterval: hotInterval,
|
||||
searchKeyword: searchParams?.get("q") || undefined,
|
||||
searchType,
|
||||
tag: decodeURIComponent(params?.tag),
|
||||
})
|
||||
|
||||
const hasFiltering = feedType === "latest"
|
||||
|
|
@ -301,7 +304,7 @@ export const HomeFeed: React.FC<{
|
|||
) : !feed.data?.pages[0]?.count ? (
|
||||
<EmptyState />
|
||||
) : (
|
||||
<div className="xlog-posts !-mt-0">
|
||||
<div className="xlog-posts my-8">
|
||||
<Virtuoso
|
||||
overscan={5}
|
||||
endReached={() => feed.hasNextPage && feed.fetchNextPage()}
|
||||
|
|
@ -309,16 +312,20 @@ export const HomeFeed: React.FC<{
|
|||
data={feed.data?.pages}
|
||||
itemContent={(_, posts) => {
|
||||
if (!posts?.list.length) return <div className="h-[1px]"></div>
|
||||
return posts?.list.map((post) => {
|
||||
return (
|
||||
<MemoedPost
|
||||
key={`${post.characterId}-${post.noteId}`}
|
||||
post={post}
|
||||
filtering={aiFiltering ? 60 : 0}
|
||||
keyword={searchParams?.get("q") || undefined}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div className="space-y-8 mb-8">
|
||||
{posts?.list.map((post) => {
|
||||
return (
|
||||
<MemoedPost
|
||||
key={`${post.characterId}-${post.noteId}`}
|
||||
post={post}
|
||||
filtering={aiFiltering ? 60 : 0}
|
||||
keyword={searchParams?.get("q") || undefined}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
></Virtuoso>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,13 @@ import { ExpandedNote } from "~/lib/types"
|
|||
|
||||
import filter from "../../data/filter.json"
|
||||
|
||||
export type FeedType = "latest" | "following" | "topic" | "hot" | "search"
|
||||
export type FeedType =
|
||||
| "latest"
|
||||
| "following"
|
||||
| "topic"
|
||||
| "hot"
|
||||
| "search"
|
||||
| "tag"
|
||||
export type SearchType = "latest" | "hot"
|
||||
|
||||
export async function getFeed({
|
||||
|
|
@ -20,6 +26,7 @@ export async function getFeed({
|
|||
daysInterval,
|
||||
searchKeyword,
|
||||
searchType,
|
||||
tag,
|
||||
}: {
|
||||
type?: FeedType
|
||||
cursor?: string
|
||||
|
|
@ -29,6 +36,7 @@ export async function getFeed({
|
|||
daysInterval?: number
|
||||
searchKeyword?: string
|
||||
searchType?: SearchType
|
||||
tag?: string
|
||||
}) {
|
||||
if (type === "search" && !searchKeyword) {
|
||||
type = "latest"
|
||||
|
|
@ -258,6 +266,41 @@ export async function getFeed({
|
|||
}),
|
||||
)
|
||||
|
||||
return {
|
||||
list,
|
||||
cursor: result.cursor,
|
||||
count: result.count,
|
||||
}
|
||||
}
|
||||
case "tag": {
|
||||
if (!tag) {
|
||||
return {
|
||||
list: [],
|
||||
cursor: "",
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
let result = await indexer.getNotes({
|
||||
sources: "xlog",
|
||||
tags: ["post", tag],
|
||||
limit,
|
||||
cursor,
|
||||
includeCharacter: true,
|
||||
})
|
||||
|
||||
result.list = result.list.filter(
|
||||
(note) => !filter.latest.includes(note.characterId),
|
||||
)
|
||||
|
||||
const list = await Promise.all(
|
||||
result.list.map(async (page: any) => {
|
||||
const expand = await expandCrossbellNote(page, false, true)
|
||||
delete expand.metadata?.content.content
|
||||
return expand
|
||||
}),
|
||||
)
|
||||
|
||||
return {
|
||||
list,
|
||||
cursor: result.cursor,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export const useGetFeed = (data?: {
|
|||
daysInterval?: number
|
||||
searchKeyword?: string
|
||||
searchType?: homeModel.SearchType
|
||||
tag?: string
|
||||
}) => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["getFeed", data],
|
||||
|
|
|
|||
Loading…
Reference in New Issue