mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-27 10:14:45 +01:00
feat: connect feed filters apis with ui, change filters list style
This commit is contained in:
@@ -18,7 +18,7 @@ export default function HackathonsPage() {
|
||||
take: 10,
|
||||
skip: 0,
|
||||
sortBy: sortByFilter,
|
||||
category: topicsFilter
|
||||
topic: Number(topicsFilter)
|
||||
},
|
||||
})
|
||||
const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed')
|
||||
|
||||
@@ -12,7 +12,7 @@ interface Props {
|
||||
export default function CommentCard({ comment, onReply }: Props) {
|
||||
return (
|
||||
<div className="border rounded-12 p-24">
|
||||
<Header author={comment.author} date={comment.created_at} />
|
||||
<Header author={comment.author} date={comment.createdAt} />
|
||||
<p className="text-body4 mt-16">
|
||||
{comment.body}
|
||||
</p>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Author } from "src/features/Posts/types";
|
||||
export interface Comment {
|
||||
id: number
|
||||
author: Author
|
||||
created_at: string
|
||||
createdAt: string
|
||||
body: string
|
||||
votes_count: number
|
||||
parentId: number | null
|
||||
|
||||
@@ -12,7 +12,7 @@ export type BountyCardType = Pick<Bounty,
|
||||
| 'type'
|
||||
| 'title'
|
||||
| 'cover_image'
|
||||
| 'date'
|
||||
| 'createdAt'
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
@@ -33,7 +33,7 @@ export default function BountyCard({ bounty }: Props) {
|
||||
<div className="bg-white rounded-12 overflow-hidden border">
|
||||
<img src={bounty.cover_image} className='h-[200px] w-full object-cover bg-gray-100' alt="" />
|
||||
<div className="p-24">
|
||||
<Header author={bounty.author} date={bounty.date} />
|
||||
<Header author={bounty.author} date={bounty.createdAt} />
|
||||
<div className="flex flex-col gap-8 md:gap-0 md:flex-row justify-between">
|
||||
<div>
|
||||
<Link to={`/blog/post/Bounty/${bounty.id}`}>
|
||||
|
||||
@@ -6,7 +6,7 @@ interface Props {
|
||||
author: {
|
||||
id: number,
|
||||
name: string,
|
||||
image: string
|
||||
avatar: string
|
||||
}
|
||||
date: string;
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
@@ -27,21 +27,25 @@ const nameSize: UnionToObjectKeys<Props, 'size'> = {
|
||||
|
||||
export default function Header({
|
||||
size = 'md',
|
||||
showTimeAgo = true,
|
||||
showTimeAgo = false,
|
||||
...props }: Props) {
|
||||
|
||||
const passedTime = dayjs().diff(props.date, 'hour');
|
||||
const dateToShow = passedTime < 24 ?
|
||||
`${dayjs().diff(props.date, 'hour')}h ago`
|
||||
:
|
||||
dayjs(props.date).format('MMMM DD');
|
||||
|
||||
const dateToShow = () => {
|
||||
const passedTime = dayjs().diff(props.date, 'hour');
|
||||
if (passedTime === 0) return 'now';
|
||||
if (passedTime < 24) return `${dayjs().diff(props.date, 'hour')}h ago`
|
||||
return dayjs(props.date).format('MMMM DD');
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='flex gap-8'>
|
||||
<Avatar width={avatarSize[size]} src={props.author.image} />
|
||||
<Avatar width={avatarSize[size]} src={props.author.avatar} />
|
||||
<div>
|
||||
<p className={`${nameSize[size]} text-black font-medium`}>{props.author.name}</p>
|
||||
<p className={`text-body6 text-gray-600`}>{dateToShow}</p>
|
||||
<p className={`text-body6 text-gray-600`}>{dateToShow()}</p>
|
||||
</div>
|
||||
{/* {showTimeAgo && <p className={`${nameSize[size]} text-gray-500 ml-auto `}>
|
||||
{dayjs().diff(props.date, 'hour') < 24 ? `${dayjs().diff(props.date, 'hour')}h ago` : undefined}
|
||||
|
||||
@@ -11,7 +11,7 @@ export type QuestionCardType = Pick<Question,
|
||||
| 'id'
|
||||
| 'type'
|
||||
| 'title'
|
||||
| 'date'
|
||||
| 'createdAt'
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
@@ -22,7 +22,7 @@ export type QuestionCardType = Pick<Question,
|
||||
| 'id'
|
||||
| 'author'
|
||||
| 'body'
|
||||
| 'created_at'
|
||||
| 'createdAt'
|
||||
>>
|
||||
};
|
||||
interface Props {
|
||||
@@ -33,7 +33,7 @@ export default function QuestionCard({ question }: Props) {
|
||||
<div className="bg-white rounded-12 overflow-hidden border">
|
||||
{/* <img src={question.cover_image} className='h-[200px] w-full object-cover' alt="" /> */}
|
||||
<div className="p-24">
|
||||
<Header author={question.author} date={question.date} />
|
||||
<Header author={question.author} date={question.createdAt} />
|
||||
<div className="flex justify-between">
|
||||
<Link to={`/blog/post/Question/${question.id}`}>
|
||||
<h2 className="text-h5 font-bolder mt-16">{question.title}</h2>
|
||||
@@ -61,7 +61,7 @@ export default function QuestionCard({ question }: Props) {
|
||||
<div className="flex p-16 mt-16 flex-col gap-10 bg-gray-50">
|
||||
<div className="flex flex-col gap-10">
|
||||
{question.comments.slice(0, 2).map(comment => <div key={comment.id} className="border-b last-of-type:border-b-0 pb-8 " >
|
||||
<Header author={comment.author} size='sm' date={comment.created_at} />
|
||||
<Header author={comment.author} size='sm' date={comment.createdAt} />
|
||||
<p className="text-body5 text-gray-600 mt-8">{trimText(comment.body, 80)}</p>
|
||||
</div>)}
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ export type StoryCardType = Pick<Story,
|
||||
| 'type'
|
||||
| 'title'
|
||||
| 'cover_image'
|
||||
| 'date'
|
||||
| 'createdAt'
|
||||
| 'author'
|
||||
| 'excerpt'
|
||||
| 'votes_count'
|
||||
@@ -25,7 +25,7 @@ export default function StoryCard({ story }: Props) {
|
||||
<div className="bg-white rounded-12 overflow-hidden border">
|
||||
<img src={story.cover_image} className='h-[200px] w-full object-cover' alt="" />
|
||||
<div className="p-24">
|
||||
<Header author={story.author} date={story.date} />
|
||||
<Header author={story.author} date={story.createdAt} />
|
||||
<Link to={`/blog/post/Story/${story.id}`}>
|
||||
<h2 className="text-h5 font-bolder mt-16">{story.title}</h2>
|
||||
</Link>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function TrendingCard() {
|
||||
trendingPosts.data?.getTrendingPosts.map(post => {
|
||||
return <Link key={post.id} to={`/blog/post/${post.__typename}/${post.id}`} className="border-b pb-4 last-of-type:border-b-0">
|
||||
<li className="flex items-start gap-8">
|
||||
<Avatar width={24} src={post.author.image} />
|
||||
<Avatar width={24} src={post.author.avatar} />
|
||||
<p className="text-body5 font-medium">{post.title}</p>
|
||||
</li>
|
||||
</Link>
|
||||
|
||||
@@ -5,7 +5,7 @@ query TrendingPosts {
|
||||
title
|
||||
author {
|
||||
id
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
... on Bounty {
|
||||
@@ -13,7 +13,7 @@ query TrendingPosts {
|
||||
title
|
||||
author {
|
||||
id
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ query TrendingPosts {
|
||||
title
|
||||
author {
|
||||
id
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useFeedQuery } from 'src/graphql'
|
||||
import { useAppSelector, useInfiniteQuery } from 'src/utils/hooks'
|
||||
import PostsList from '../../Components/PostsList/PostsList'
|
||||
import TrendingCard from '../../Components/TrendingCard/TrendingCard'
|
||||
import PopularCategories from './PopularCategories/PopularCategories'
|
||||
import PopularTopicsFilter from './PopularTopicsFilter/PopularTopicsFilter'
|
||||
import SortBy from './SortBy/SortBy'
|
||||
import styles from './styles.module.scss'
|
||||
|
||||
@@ -12,15 +12,15 @@ import styles from './styles.module.scss'
|
||||
export default function FeedPage() {
|
||||
|
||||
const [sortByFilter, setSortByFilter] = useState('all')
|
||||
const [categoryFilter, setCategoryFilter] = useState('all')
|
||||
const [topicFilter, setTopicFilter] = useState<number | null>(null)
|
||||
|
||||
|
||||
const feedQuery = useFeedQuery({
|
||||
variables: {
|
||||
take: 10,
|
||||
take: 3,
|
||||
skip: 0,
|
||||
sortBy: sortByFilter,
|
||||
category: categoryFilter
|
||||
topic: topicFilter
|
||||
},
|
||||
})
|
||||
const { fetchMore, isFetchingMore } = useInfiniteQuery(feedQuery, 'getFeed')
|
||||
@@ -42,9 +42,9 @@ export default function FeedPage() {
|
||||
<SortBy
|
||||
filterChanged={setSortByFilter}
|
||||
/>
|
||||
<hr className="my-24 bg-gray-100" />
|
||||
<PopularCategories
|
||||
filterChanged={setCategoryFilter}
|
||||
<div className="my-24"></div>
|
||||
<PopularTopicsFilter
|
||||
filterChanged={setTopicFilter}
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import PopularCategories from './PopularCategories';
|
||||
|
||||
export default {
|
||||
title: 'Posts/Feed Page/Components/PopularCategories',
|
||||
component: PopularCategories,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof PopularCategories>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof PopularCategories> = (args) => <div className="max-w-[326px]"><PopularCategories {...args as any} ></PopularCategories></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
|
||||
const filters = [
|
||||
{
|
||||
text: "🔥 All",
|
||||
value: 'all'
|
||||
}, {
|
||||
text: "Lightning Network",
|
||||
value: 'lightning-network'
|
||||
}, {
|
||||
text: "Bitcoin",
|
||||
value: 'bitcoin'
|
||||
}, {
|
||||
text: "Cybersecurity",
|
||||
value: 'cybersecurity'
|
||||
}, {
|
||||
text: "Bounties",
|
||||
value: 'bounties'
|
||||
}, {
|
||||
text: "Grants",
|
||||
value: 'Grants'
|
||||
},
|
||||
]
|
||||
|
||||
interface Props {
|
||||
filterChanged?: (newFilter: string) => void
|
||||
}
|
||||
|
||||
export default function PopularCategories({ filterChanged }: Props) {
|
||||
|
||||
const [selected, setSelected] = useState(filters[0].value);
|
||||
|
||||
const filterClicked = (newValue: string) => {
|
||||
if (selected === newValue)
|
||||
return
|
||||
setSelected(newValue);
|
||||
filterChanged?.(newValue);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className=''>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Popular Categories</p>
|
||||
<ul>
|
||||
{filters.map((f, idx) => <li
|
||||
key={f.value}
|
||||
className={`p-12 rounded-8 cursor-pointer font-bold ${f.value === selected && 'bg-gray-100'}`}
|
||||
onClick={() => filterClicked(f.value)}
|
||||
>
|
||||
{f.text}
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
|
||||
import PopularTopicsFilter from './PopularTopicsFilter';
|
||||
|
||||
export default {
|
||||
title: 'Posts/Feed Page/Components/Popular Topics Filter',
|
||||
component: PopularTopicsFilter,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
} as ComponentMeta<typeof PopularTopicsFilter>;
|
||||
|
||||
|
||||
const Template: ComponentStory<typeof PopularTopicsFilter> = (args) => <div className="max-w-[326px]"><PopularTopicsFilter {...args as any} ></PopularTopicsFilter></div>
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import React, { useState } from 'react'
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { usePopularTopicsQuery } from 'src/graphql';
|
||||
|
||||
const filters = [
|
||||
{
|
||||
text: "🔥 All",
|
||||
value: 0
|
||||
}, {
|
||||
text: "Lightning Network",
|
||||
value: 1
|
||||
}, {
|
||||
text: "Bitcoin",
|
||||
value: 2
|
||||
}, {
|
||||
text: "Cybersecurity",
|
||||
value: 3
|
||||
}, {
|
||||
text: "Bounties",
|
||||
value: 4
|
||||
}, {
|
||||
text: "Grants",
|
||||
value: 5
|
||||
},
|
||||
]
|
||||
|
||||
interface Props {
|
||||
filterChanged?: (newFilter: number) => void
|
||||
}
|
||||
|
||||
export default function PopularTopicsFilter({ filterChanged }: Props) {
|
||||
|
||||
const [selected, setSelected] = useState(filters[0].value);
|
||||
|
||||
const topicsQuery = usePopularTopicsQuery();
|
||||
|
||||
|
||||
const filterClicked = (newValue: number) => {
|
||||
if (selected === newValue)
|
||||
return
|
||||
setSelected(newValue);
|
||||
filterChanged?.(newValue);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='bg-white border rounded-12 p-16'>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Topics</p>
|
||||
<ul className=' flex flex-col gap-16'>
|
||||
{topicsQuery.loading ?
|
||||
Array(4).fill(0).map((_, idx) => <li
|
||||
key={idx}
|
||||
className={`flex items-start rounded-8 font-bold`}
|
||||
|
||||
>
|
||||
<span className='bg-gray-50 rounded-8 w-40 h-40 text-center py-8'> </span>
|
||||
<span className="self-center px-16"><Skeleton width={'10ch'} />
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
:
|
||||
topicsQuery.data?.popularTopics.map((f, idx) => <li
|
||||
key={f.id}
|
||||
className={`flex items-start rounded-8 cursor-pointer font-bold ${f.id === selected && 'bg-gray-50'}`}
|
||||
onClick={() => filterClicked(f.id)}
|
||||
>
|
||||
<span className='bg-gray-50 rounded-8 w-40 h-40 text-center py-8'>{f.icon}</span>
|
||||
<span className="self-center px-16">
|
||||
{f.title}
|
||||
</span>
|
||||
</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
query PopularTopics {
|
||||
popularTopics {
|
||||
id
|
||||
title
|
||||
icon
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export default function SortBy({ filterChanged }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className=''>
|
||||
<div className='bg-white border rounded-12 p-16'>
|
||||
<p className="text-body2 font-bolder text-black mb-16">Sort By</p>
|
||||
<ul>
|
||||
{filters.map((f, idx) => <li
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, category: $category) {
|
||||
query Feed($take: Int, $skip: Int, $sortBy: String, $topic: Int) {
|
||||
getFeed(take: $take, skip: $skip, sortBy: $sortBy, topic: $topic) {
|
||||
... on Story {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
excerpt
|
||||
tags {
|
||||
@@ -22,11 +22,11 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
|
||||
... on Bounty {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
excerpt
|
||||
tags {
|
||||
@@ -43,11 +43,11 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
|
||||
... on Question {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
excerpt
|
||||
tags {
|
||||
@@ -59,12 +59,12 @@ query Feed($take: Int, $skip: Int, $sortBy: String, $category: String) {
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
created_at
|
||||
createdAt
|
||||
body
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function AuthorCard({ author }: Props) {
|
||||
return (
|
||||
<div className="bg-white p-16 border rounded-8">
|
||||
<div className='flex gap-8'>
|
||||
<Avatar width={48} src={author.image} />
|
||||
<Avatar width={48} src={author.avatar} />
|
||||
<div>
|
||||
<p className={`'text-body4' text-black font-medium`}>{author.name}</p>
|
||||
<p className={`text-body6 text-gray-600`}>Joined on {dayjs(author.join_date).format('MMMM DD, YYYY')}</p>
|
||||
|
||||
@@ -9,6 +9,8 @@ import Button from "src/Components/Button/Button";
|
||||
import { FiGithub, FiShare2 } from "react-icons/fi";
|
||||
import BountyApplicants from "./BountyApplicants";
|
||||
import VoteButton from "src/Components/VoteButton/VoteButton";
|
||||
import { RiFlashlightLine } from "react-icons/ri";
|
||||
import { numberFormatter } from "src/utils/helperFunctions";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -21,14 +23,16 @@ export default function BountyPageContent({ bounty }: Props) {
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex flex-col gap-24">
|
||||
<Header size="lg" showTimeAgo={false} author={bounty.author} date={bounty.date} />
|
||||
<Header size="lg" showTimeAgo={false} author={bounty.author} date={bounty.createdAt} />
|
||||
<h1 className="text-h2 font-bolder">{bounty.title} <Badge color="none" size="sm" className="bg-warning-500 text-black">Bounty</Badge></h1>
|
||||
<div className="">
|
||||
<span className="text-body4 text-gray-600 font-bolder">Reward: </span>
|
||||
<span className="text-body4 text-purple-500 font-medium">{bounty.reward_amount} sats</span>
|
||||
</div>
|
||||
<div className="flex gap-24 items-center">
|
||||
<VoteButton initVotes={bounty.votes_count} />
|
||||
<div className="text-black font-medium">
|
||||
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(bounty.votes_count)} votes</span>
|
||||
</div>
|
||||
<div className="text-black font-medium">
|
||||
<BiComment /> <span className="align-middle text-body5">32 Comments</span>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { BsBookmark } from "react-icons/bs"
|
||||
import { MdIosShare, MdLocalFireDepartment } from "react-icons/md"
|
||||
import { MdIosShare } from "react-icons/md"
|
||||
import VoteButton from "src/Components/VoteButton/VoteButton"
|
||||
|
||||
interface Props {
|
||||
votes_count: number
|
||||
}
|
||||
|
||||
|
||||
export default function PostActions() {
|
||||
export default function PostActions(props: Props) {
|
||||
|
||||
const actions = [
|
||||
{
|
||||
@@ -19,7 +21,7 @@ export default function PostActions() {
|
||||
|
||||
return (
|
||||
<ul className="bg-white rounded-12 p-16 border flex justify-around md:flex-col gap-32">
|
||||
<VoteButton initVotes={123} direction='vertical' fillType="upDown" />
|
||||
<VoteButton initVotes={props.votes_count} direction='vertical' fillType="upDown" />
|
||||
{actions.map((action, idx) => <li
|
||||
className={`py-8 px-20 text-body5 flex flex-col justify-center items-center cursor-pointer rounded-8
|
||||
${'text-gray-500 hover:bg-gray-50 active:bg-gray-100'}`}>
|
||||
|
||||
@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge";
|
||||
import { BiComment } from "react-icons/bi";
|
||||
import { RiFlashlightLine } from "react-icons/ri";
|
||||
import { CommentsSection } from "src/features/Posts/Components/Comments";
|
||||
import { numberFormatter } from "src/utils/helperFunctions";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -17,7 +18,7 @@ export default function QuestionPageContent({ question }: Props) {
|
||||
<>
|
||||
<div id="content" className="bg-white p-32 border rounded-16">
|
||||
<div className="flex flex-col gap-24">
|
||||
<Header size="lg" showTimeAgo={false} author={question.author} date={question.date} />
|
||||
<Header size="lg" showTimeAgo={false} author={question.author} date={question.createdAt} />
|
||||
<h1 className="text-h2 font-bolder">{question.title}</h1>
|
||||
<div className="flex gap-8">
|
||||
{question.tags.map(tag => <Badge key={tag.id} size='sm'>
|
||||
@@ -26,7 +27,7 @@ export default function QuestionPageContent({ question }: Props) {
|
||||
</div>
|
||||
<div className="flex gap-24">
|
||||
<div className="text-black font-medium">
|
||||
<RiFlashlightLine /> <span className="align-middle text-body5">{question.votes_count} votes</span>
|
||||
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(question.votes_count)} votes</span>
|
||||
</div>
|
||||
<div className="text-black font-medium">
|
||||
<BiComment /> <span className="align-middle text-body5">32 Comments</span>
|
||||
@@ -38,9 +39,9 @@ export default function QuestionPageContent({ question }: Props) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="comments" className="mt-10">
|
||||
{/* <div id="comments" className="mt-10">
|
||||
<CommentsSection comments={question.comments} />
|
||||
</div>
|
||||
</div> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import Badge from "src/Components/Badge/Badge";
|
||||
import { BiComment } from "react-icons/bi";
|
||||
import { RiFlashlightLine } from "react-icons/ri";
|
||||
import { CommentsSection } from "src/features/Posts/Components/Comments";
|
||||
import { numberFormatter } from "src/utils/helperFunctions";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -17,16 +18,16 @@ export default function StoryPageContent({ story }: Props) {
|
||||
<>
|
||||
<div id="content" className="bg-white p-32 border rounded-16">
|
||||
<div className="flex flex-col gap-24">
|
||||
<Header size="lg" showTimeAgo={false} author={story.author} date={story.date} />
|
||||
<Header size="lg" showTimeAgo={false} author={story.author} date={story.createdAt} />
|
||||
<h1 className="text-h2 font-bolder">{story.title}</h1>
|
||||
<div className="flex gap-8">
|
||||
{story.tags.length > 0 && <div className="flex gap-8">
|
||||
{story.tags.map(tag => <Badge key={tag.id} size='sm'>
|
||||
{tag.title}
|
||||
</Badge>)}
|
||||
</div>
|
||||
</div>}
|
||||
<div className="flex gap-24">
|
||||
<div className="text-black font-medium">
|
||||
<RiFlashlightLine /> <span className="align-middle text-body5">{story.votes_count} votes</span>
|
||||
<RiFlashlightLine /> <span className="align-middle text-body5">{numberFormatter(story.votes_count)} votes</span>
|
||||
</div>
|
||||
<div className="text-black font-medium">
|
||||
<BiComment /> <span className="align-middle text-body5">{story.comments_count} Comments</span>
|
||||
@@ -37,9 +38,9 @@ export default function StoryPageContent({ story }: Props) {
|
||||
<div className={`mt-42 ${styles.body}`} dangerouslySetInnerHTML={{ __html: marked.parse(story.body) }}>
|
||||
</div>
|
||||
</div>
|
||||
<div id="comments" className="mt-10 comments_col">
|
||||
{/* <div id="comments" className="mt-10 comments_col">
|
||||
<CommentsSection comments={story.comments} />
|
||||
</div>
|
||||
</div> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function PostDetailsPage() {
|
||||
top: `${navHeight + 16}px`,
|
||||
maxHeight: `calc(100vh - ${navHeight}px - 16px)`,
|
||||
}}>
|
||||
<PostActions />
|
||||
<PostActions votes_count={post.votes_count} />
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
... on Story {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
body
|
||||
tags {
|
||||
@@ -20,25 +20,25 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
comments_count
|
||||
comments {
|
||||
id
|
||||
created_at
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
... on Bounty {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
body
|
||||
tags {
|
||||
@@ -58,18 +58,18 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
... on Question {
|
||||
id
|
||||
title
|
||||
date
|
||||
createdAt
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
body
|
||||
tags {
|
||||
@@ -81,14 +81,14 @@ query PostDetails($id: Int!, $type: POST_TYPE!) {
|
||||
answers_count
|
||||
comments {
|
||||
id
|
||||
created_at
|
||||
createdAt
|
||||
body
|
||||
votes_count
|
||||
parentId
|
||||
author {
|
||||
id
|
||||
name
|
||||
image
|
||||
avatar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Tag } from "src/utils/interfaces"
|
||||
export type User = {
|
||||
id: number
|
||||
name: string
|
||||
image: string
|
||||
avatar: string
|
||||
}
|
||||
|
||||
export type Author = User & {
|
||||
@@ -14,7 +14,7 @@ export type Author = User & {
|
||||
export type PostBase1 = {
|
||||
id: number
|
||||
title: string
|
||||
date: string
|
||||
createdAt: string
|
||||
author: Author
|
||||
excerpt: string
|
||||
tags: Tag[]
|
||||
|
||||
@@ -4,14 +4,16 @@ import ProjectsSection from "./ProjectsSection/ProjectsSection";
|
||||
|
||||
export default function ExplorePage() {
|
||||
return (
|
||||
<>
|
||||
<div className="px-32">
|
||||
<Header />
|
||||
</div>
|
||||
<div className="page-container">
|
||||
|
||||
<Header />
|
||||
|
||||
{/* <div className="my-40 px-32">
|
||||
<Categories />
|
||||
</div> */}
|
||||
<ProjectsSection />
|
||||
</>
|
||||
<div className="w-full overflow-hidden">
|
||||
<ProjectsSection />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ export default function ProjectsRowSkeleton() {
|
||||
|
||||
return (
|
||||
<div className='mb-48'>
|
||||
<h3 className="font-bolder text-body3 mb-24 px-32">
|
||||
<h3 className="font-bolder text-body3 mb-24">
|
||||
<Skeleton width='10ch' />
|
||||
</h3>
|
||||
<div className="p-32 flex gap-20">
|
||||
<div className=" flex gap-20">
|
||||
{Array(5).fill(0).map((_, idx) => (
|
||||
<ProjectCardMiniSkeleton key={idx} />
|
||||
))}
|
||||
|
||||
@@ -83,13 +83,13 @@ export default function ProjectsRow({ title, categoryId, projects }: Props) {
|
||||
|
||||
return (
|
||||
<div className='mb-48'>
|
||||
<h3 className="font-bolder text-body3 mb-24 px-32">
|
||||
<h3 className="font-bolder text-body3 mb-24">
|
||||
<span className="align-middle">{title}</span>
|
||||
{categoryId > 0 && <Link to={`/category/${categoryId}`}>
|
||||
<MdDoubleArrow className='text-gray-200 ml-8 hover:cursor-pointer transform scale-y-110 scale-x-125 origin-left' />
|
||||
</Link>}
|
||||
</h3>
|
||||
<div className="px-32">
|
||||
<div className="">
|
||||
<Carousel
|
||||
showDots={false}
|
||||
autoPlay={false}
|
||||
|
||||
Reference in New Issue
Block a user