Merge branch 'feat/discover' of https://github.com/kamranahmedse/developer-roadmap into feat/discover

feat/discover
Arik Chakma 5 months ago
commit c2682e84ce
  1. 67
      src/components/DiscoverRoadmaps/DiscoverRoadmaps.tsx
  2. 2
      src/components/ExploreAIRoadmap/LoadingRoadmaps.tsx
  3. 10
      src/components/Rating/Rating.tsx

@ -10,6 +10,7 @@ import { LoadingRoadmaps } from '../ExploreAIRoadmap/LoadingRoadmaps';
import { httpGet } from '../../lib/http';
import { useToast } from '../../hooks/use-toast';
import { DiscoverRoadmapSorting } from './DiscoverRoadmapSorting';
import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal.tsx';
type DiscoverRoadmapsProps = {};
@ -103,18 +104,51 @@ export function DiscoverRoadmaps(props: DiscoverRoadmapsProps) {
setRoadmapsResponse(response);
};
const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
const roadmaps = roadmapsResponse?.data || [];
const loadingIndicator = isLoading && <LoadingRoadmaps />;
return (
<section className="container mx-auto py-3 sm:py-6">
<>
{isCreatingRoadmap && (
<CreateRoadmapModal
onClose={() => {
setIsCreatingRoadmap(false);
}}
/>
)}
<div className="border-b bg-white py-7">
<div className="container text-left">
<div className="flex flex-col items-start bg-white">
<h1 className="mb-1 text-2xl font-bold sm:text-3xl">
Community Roadmaps
</h1>
<p className="text-base text-gray-500">
Browse the roadmaps created by the community or{' '}
<button
onClick={() => {
setIsCreatingRoadmap(true);
}}
className="rounded text-blue-600 underline"
>
create your own roadmap
</button>
</p>
</div>
</div>
</div>
<div className="py-3 bg-gray-50">
<section className="container mx-auto py-3">
<div className="mb-3.5 flex items-stretch justify-between gap-2.5">
<SearchRoadmap
total={roadmapsResponse?.totalCount || 0}
value={pageState.searchTerm}
isLoading={isLoading}
onValueChange={(value) => {}}
onValueChange={(value) => {
}}
/>
<DiscoverRoadmapSorting
@ -129,42 +163,49 @@ export function DiscoverRoadmaps(props: DiscoverRoadmapsProps) {
</div>
{loadingIndicator}
{roadmaps.length === 0 && !isLoading && <EmptyDiscoverRoadmaps />}
{roadmaps.length === 0 && !isLoading && <EmptyDiscoverRoadmaps/>}
{roadmaps.length > 0 && !isLoading && (
<>
<ul className="mb-4 grid grid-cols-1 items-stretch gap-2 sm:grid-cols-2 lg:grid-cols-3">
<ul className="mb-4 grid grid-cols-1 items-stretch gap-3 sm:grid-cols-2 lg:grid-cols-3">
{roadmaps.map((roadmap) => {
const roadmapLink = `/r/${roadmap.slug}`;
const totalRatings = Object.keys(
roadmap.ratings?.breakdown || [],
).reduce(
(acc: number, key: string) =>
acc + roadmap.ratings.breakdown[key as any],
0,
);
return (
<li key={roadmap._id} className="h-full">
<li key={roadmap._id} className="h-full min-h-[175px]">
<a
key={roadmap._id}
href={roadmapLink}
className="flex h-full flex-col rounded-md border transition-colors hover:bg-gray-100"
className="flex h-full flex-col rounded-lg border bg-white p-3.5 transition-colors hover:border-gray-300 hover:bg-gray-50"
target={'_blank'}
>
<div className="grow">
<h2 className="mt-2.5 px-2.5 text-base font-medium leading-tight">
<h2 className="text-balance text-base font-bold leading-tight">
{roadmap.title}
</h2>
<p className="my-2.5 px-2.5 text-sm text-gray-500">
<p className="mt-2 text-sm text-gray-500">
{roadmap.description}
</p>
</div>
<div className="flex items-center justify-between gap-2 px-2.5 py-2">
<span className="flex items-center gap-1.5 text-xs text-gray-400">
<Shapes size={15} className="inline-block" />
<div className="flex items-center justify-between gap-2">
<span className="flex items-center gap-1 text-xs text-gray-400">
<Shapes size={15} className="inline-block"/>
{Intl.NumberFormat('en-US', {
notation: 'compact',
}).format(roadmap.topicCount)}{' '}
topics
</span>
<Rating
rating={roadmap?.ratings?.average || 0}
readOnly={true}
starSize={16}
total={totalRatings}
/>
</div>
</a>
@ -188,5 +229,7 @@ export function DiscoverRoadmaps(props: DiscoverRoadmapsProps) {
</>
)}
</section>
</div>
</>
);
}

@ -4,7 +4,7 @@ export function LoadingRoadmaps() {
{new Array(21).fill(0).map((_, index) => (
<li
key={index}
className="h-[95px] animate-pulse rounded-md border bg-gray-100"
className="h-[175px] animate-pulse rounded-md border bg-gray-100"
/>
))}
</ul>

@ -7,6 +7,7 @@ type RatingProps = {
starSize?: number;
readOnly?: boolean;
className?: string;
total?: number;
};
export function Rating(props: RatingProps) {
@ -22,6 +23,10 @@ export function Rating(props: RatingProps) {
const starCount = Math.floor(stars);
const decimalWidthPercentage = Math.min((stars - starCount) * 100, 100);
if (readOnly && starCount === 0) {
return <span className="text-xs text-gray-400">No ratings yet</span>;
}
return (
<div className={cn('flex', className)}>
{[1, 2, 3, 4, 5].map((counter) => {
@ -43,6 +48,11 @@ export function Rating(props: RatingProps) {
/>
);
})}
{props.total && (
<span className="ml-1.5 text-xs text-gray-400">
({Intl.NumberFormat('en-US').format(props.total)})
</span>
)}
</div>
);
}

Loading…
Cancel
Save