Improve UI for project solutions

pull/8172/head
Kamran Ahmed 1 week ago
parent 314eb5d7d2
commit 5cc4b834d1
  1. 12
      src/components/Projects/ListProjectSolutions.tsx
  2. 54
      src/components/Projects/ProjectSolutionRow.tsx

@ -213,6 +213,13 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
const selectedLanguage = pageState.language; const selectedLanguage = pageState.language;
const setSelectedLanguage = (language: string) => {
setPageState((prev) => ({
...prev,
language: prev.language === language ? '' : language,
}));
};
return ( return (
<div className="mb-4 overflow-hidden rounded-lg border bg-white p-3 sm:p-5"> <div className="mb-4 overflow-hidden rounded-lg border bg-white p-3 sm:p-5">
{leavingRoadmapModal} {leavingRoadmapModal}
@ -221,7 +228,9 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
<h1 className="mb-1 text-xl font-semibold"> <h1 className="mb-1 text-xl font-semibold">
{projectData.title} Solutions {projectData.title} Solutions
</h1> </h1>
<p className="text-sm text-gray-500">{projectData.description}</p> <p className="text-sm text-gray-500">
Solutions submitted by the community
</p>
</div> </div>
{!isLoading && ( {!isLoading && (
<div className="flex flex-shrink-0 items-center gap-2"> <div className="flex flex-shrink-0 items-center gap-2">
@ -260,6 +269,7 @@ export function ListProjectSolutions(props: ListProjectSolutionsProps) {
counter={counter} counter={counter}
onVote={handleSubmitVote} onVote={handleSubmitVote}
onVisitSolution={setShowLeavingRoadmapModal} onVisitSolution={setShowLeavingRoadmapModal}
onLanguageClick={setSelectedLanguage}
/> />
))} ))}
</div> </div>

@ -43,17 +43,17 @@ type ProjectSolutionRowProps = {
counter: number; counter: number;
onVote: (solutionId: string, voteType: AllowedVoteType) => void; onVote: (solutionId: string, voteType: AllowedVoteType) => void;
onVisitSolution: (solution: ProjectSolutionRowProps['solution']) => void; onVisitSolution: (solution: ProjectSolutionRowProps['solution']) => void;
onLanguageClick?: (language: string) => void;
}; };
export function ProjectSolutionRow(props: ProjectSolutionRowProps) { export function ProjectSolutionRow(props: ProjectSolutionRowProps) {
const { solution, counter, onVote, onVisitSolution } = props; const { solution, counter, onVote, onVisitSolution, onLanguageClick } = props;
const avatar = solution.user.avatar || ''; const avatar = solution.user.avatar || '';
return ( return (
<div className="flex flex-col gap-2 py-2 text-sm text-gray-500"> <div className="group flex flex-col border-gray-100 px-3 py-2.5 text-sm hover:bg-gray-50/50 sm:flex-row sm:justify-between">
<div className="flex flex-col justify-between gap-2 text-sm text-gray-500 sm:flex-row sm:items-center sm:gap-0"> <div className="flex min-w-0 items-start gap-3">
<div className="flex items-center gap-1.5">
<img <img
src={ src={
avatar avatar
@ -61,19 +61,27 @@ export function ProjectSolutionRow(props: ProjectSolutionRowProps) {
: '/images/default-avatar.png' : '/images/default-avatar.png'
} }
alt={solution.user.name} alt={solution.user.name}
className="mr-0.5 h-7 w-7 rounded-full" className="h-7 w-7 flex-shrink-0 rounded-full sm:h-8 sm:w-8"
/> />
<span className="font-medium text-black">{solution.user.name}</span> <div className="min-w-0 flex-auto">
<span className="hidden sm:inline"> <div className="flex flex-wrap items-baseline gap-x-1.5 gap-y-0.5">
<span className="max-w-[150px] truncate font-medium text-gray-900 sm:max-w-[180px]">
{solution.user.name}
</span>
<span className="hidden truncate text-xs text-gray-500 sm:block sm:text-sm">
{submittedAlternatives[counter % submittedAlternatives.length] || {submittedAlternatives[counter % submittedAlternatives.length] ||
'submitted their solution'} 'submitted their solution'}
</span>{' '} </span>
<span className="flex-grow text-right text-gray-400 sm:flex-grow-0 sm:text-left sm:font-medium sm:text-black"> <span
{getRelativeTimeString(solution?.submittedAt!)} className="text-xs text-gray-400"
title={new Date(solution?.submittedAt!).toLocaleString()}
>
· {getRelativeTimeString(solution?.submittedAt!)}
</span> </span>
</div> </div>
<div className="flex items-center justify-end gap-1"> <div className="mt-2.5 flex gap-1.5">
<div className="flex gap-1">
<span className="flex shrink-0 overflow-hidden rounded-full border"> <span className="flex shrink-0 overflow-hidden rounded-full border">
<VoteButton <VoteButton
icon={ThumbsUp} icon={ThumbsUp}
@ -94,17 +102,35 @@ export function ProjectSolutionRow(props: ProjectSolutionRowProps) {
}} }}
/> />
</span> </span>
</div>
<button <button
className="ml-1 flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white" className="flex items-center gap-1 rounded-full border px-2 py-1 text-xs text-black transition-colors hover:border-black hover:bg-black hover:text-white"
onClick={() => { onClick={() => {
onVisitSolution(solution); onVisitSolution(solution);
}} }}
> >
<GitHubIcon className="h-4 w-4 text-current" /> <GitHubIcon className="h-3.5 w-3.5 text-current" />
Visit Solution <span>Visit Solution</span>
</button>
</div>
</div>
</div>
<div className="mt-2.5 hidden sm:mt-0 sm:block sm:pl-4">
{solution.languages && solution.languages.length > 0 && (
<div className="flex flex-wrap items-center gap-1.5">
{solution.languages.slice(0, 2).map((lang) => (
<button
key={lang}
onClick={() => onLanguageClick?.(lang)}
className="inline-flex items-center rounded-md border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-700 transition-colors hover:border-gray-300 hover:bg-gray-50 hover:text-gray-900"
>
{lang}
</button> </button>
))}
</div> </div>
)}
</div> </div>
</div> </div>
); );

Loading…
Cancel
Save