Add empty projects listing and cards

feat/projects-list
Kamran Ahmed 4 months ago
parent 0ee2cf9b8f
commit 5a4d1220fe
  1. 25
      src/components/Badge.tsx
  2. 2
      src/components/Projects/EmptyProjects.tsx
  3. 19
      src/components/Projects/ProjectCard.tsx
  4. 95
      src/components/Projects/ProjectsList.tsx
  5. 21
      src/pages/[roadmapId]/projects.astro

@ -0,0 +1,25 @@
type BadgeProps = {
variant: 'blue' | 'green' | 'red' | 'yellow' | 'grey' | 'white';
text: string;
};
export function Badge(type: BadgeProps) {
const { variant, text } = type;
const colors = {
blue: 'bg-blue-100 text-blue-700',
green: 'bg-green-100 text-green-700',
red: 'bg-red-100 text-red-700',
yellow: 'bg-yellow-100 text-yellow-700',
grey: 'bg-gray-100 text-gray-700',
white: 'bg-white text-black',
};
return (
<span
className={`rounded-md border ${colors[variant]} px-1 py-0.5 text-xs tracking-wide`}
>
{text}
</span>
);
}

@ -15,7 +15,7 @@ export function EmptyProjects() {
}, []); }, []);
return ( return (
<div className="flex flex-col items-center justify-center"> <div className="relative my-2.5 flex min-h-[400px] flex-col items-center justify-center rounded-lg border bg-white">
<FolderKanbanIcon className="h-14 w-14 text-gray-300" strokeWidth={1.5} /> <FolderKanbanIcon className="h-14 w-14 text-gray-300" strokeWidth={1.5} />
<h2 className="mb-0.5 mt-2 text-center text-base font-medium text-gray-900 sm:text-xl"> <h2 className="mb-0.5 mt-2 text-center text-base font-medium text-gray-900 sm:text-xl">
<span className="hidden sm:inline">Projects are coming soon!</span> <span className="hidden sm:inline">Projects are coming soon!</span>

@ -0,0 +1,19 @@
import { Badge } from '../Badge.tsx';
export function ProjectCard() {
return (
<a
href="#"
className="flex flex-col rounded-md border bg-white p-3 transition-colors hover:border-gray-300 hover:bg-gray-50"
>
<span className="flex justify-between gap-1.5">
<Badge variant={'yellow'} text={'Beginner'} />
<Badge variant={'grey'} text={'API'} />
</span>
<span className="mb-1 mt-2.5 font-medium">Bank Application</span>
<span className="text-sm text-gray-500">
Create a simple CLI to collect and calculate the taxes.
</span>
</a>
);
}

@ -0,0 +1,95 @@
import { ProjectCard } from './ProjectCard.tsx';
import { Diff, HeartHandshake } from 'lucide-react';
import { cn } from '../../lib/classname.ts';
import { useState } from 'react';
type DifficultyButtonProps = {
difficulty: 'beginner' | 'intermediate' | 'senior';
isActive?: boolean;
onClick?: () => void;
};
function DifficultyButton(props: DifficultyButtonProps) {
const { difficulty, onClick, isActive } = props;
return (
<button
onClick={onClick}
className={cn(
'rounded-md border bg-white px-3 py-1 text-sm capitalize transition-colors hover:border-gray-300 hover:bg-gray-100',
{
'border-black bg-gray-100 hover:border-black hover:bg-gray-100 hover:text-black':
isActive,
},
)}
>
{difficulty}
</button>
);
}
export function ProjectsList() {
const [difficulty, setDifficulty] = useState<
'beginner' | 'intermediate' | 'senior'
>();
return (
<div className="flex flex-col">
<div className="my-2.5 flex items-center justify-between">
<div className="flex items-center gap-1">
<DifficultyButton
onClick={() => {
setDifficulty('beginner');
}}
difficulty={'beginner'}
isActive={difficulty === 'beginner'}
/>
<DifficultyButton
onClick={() => {
setDifficulty('intermediate');
}}
difficulty={'intermediate'}
isActive={difficulty === 'intermediate'}
/>
<DifficultyButton
onClick={() => {
setDifficulty('senior');
}}
difficulty={'senior'}
isActive={difficulty === 'senior'}
/>
</div>
<a
href={''}
className="flex items-center gap-2 rounded-md border border-transparent px-2 py-0.5 text-sm underline underline-offset-2 hover:bg-black hover:text-white hover:no-underline"
>
<HeartHandshake className="h-4 w-4" />
Submit a Project Idea
</a>
</div>
<div className="mb-24 grid grid-cols-3 gap-1.5">
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
<ProjectCard />
</div>
</div>
);
}

@ -6,6 +6,7 @@ import RelatedRoadmaps from '../../components/RelatedRoadmaps.astro';
import RoadmapHeader from '../../components/RoadmapHeader.astro'; import RoadmapHeader from '../../components/RoadmapHeader.astro';
import { FolderKanbanIcon } from 'lucide-react'; import { FolderKanbanIcon } from 'lucide-react';
import { EmptyProjects } from '../../components/Projects/EmptyProjects'; import { EmptyProjects } from '../../components/Projects/EmptyProjects';
import { ProjectsList } from '../../components/Projects/ProjectsList';
import ShareIcons from '../../components/ShareIcons/ShareIcons.astro'; import ShareIcons from '../../components/ShareIcons/ShareIcons.astro';
import { TopicDetail } from '../../components/TopicDetail/TopicDetail'; import { TopicDetail } from '../../components/TopicDetail/TopicDetail';
import { UserProgressModal } from '../../components/UserProgress/UserProgressModal'; import { UserProgressModal } from '../../components/UserProgress/UserProgressModal';
@ -46,6 +47,15 @@ const ogImageUrl =
group: 'roadmap', group: 'roadmap',
resourceId: roadmapId, resourceId: roadmapId,
}); });
const projects = ['a'];
const descriptionNoun = {
'AI and Data Scientist': 'AI and Data Science',
'Game Developer': 'Game Development',
'Technical Writer': 'Technical Writing',
'Product Manager': 'Product Management',
};
--- ---
<BaseLayout <BaseLayout
@ -61,8 +71,8 @@ const ogImageUrl =
> >
<div class='bg-gray-50'> <div class='bg-gray-50'>
<RoadmapHeader <RoadmapHeader
title={roadmapData.title} title={`${roadmapData.briefTitle} Projects`}
description={roadmapData.description} description={`Project ideas to take you from beginner to advanced in ${descriptionNoun[roadmapData.briefTitle] || roadmapData.briefTitle}`}
note={roadmapData.note} note={roadmapData.note}
tnsBannerLink={roadmapData.tnsBannerLink} tnsBannerLink={roadmapData.tnsBannerLink}
roadmapId={roadmapId} roadmapId={roadmapId}
@ -74,11 +84,8 @@ const ogImageUrl =
/> />
<div class='container'> <div class='container'>
<div {projects.length === 0 && <EmptyProjects client:load />}
class='relative my-2.5 flex min-h-[400px] flex-col items-center justify-center rounded-lg border bg-white' {projects.length > 0 && <ProjectsList client:load />}
>
<EmptyProjects client:load />
</div>
</div> </div>
</div> </div>
</BaseLayout> </BaseLayout>

Loading…
Cancel
Save