mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-09 10:46:52 +02:00
Fix roadmap page
This commit is contained in:
26
src/components/ReactIcons/DropdownIcon.tsx
Normal file
26
src/components/ReactIcons/DropdownIcon.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { cn } from '../../lib/classname';
|
||||||
|
|
||||||
|
type DropdownIconProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function DropdownIcon(props: DropdownIconProps) {
|
||||||
|
const { className } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
strokeWidth="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
className={cn('h-5 w-5', className)}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M19.5 8.25l-7.5 7.5-7.5-7.5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
@@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from 'react';
|
|||||||
import type { TeamDocument } from '../CreateTeam/CreateTeamForm';
|
import type { TeamDocument } from '../CreateTeam/CreateTeamForm';
|
||||||
import type { TeamResourceConfig } from '../CreateTeam/RoadmapSelector';
|
import type { TeamResourceConfig } from '../CreateTeam/RoadmapSelector';
|
||||||
import { httpGet } from '../../lib/http';
|
import { httpGet } from '../../lib/http';
|
||||||
import DropdownIcon from '../../icons/dropdown.svg';
|
// import DropdownIcon from '../../icons/dropdown.svg';
|
||||||
import {
|
import {
|
||||||
clearResourceProgress,
|
clearResourceProgress,
|
||||||
refreshProgressCounters,
|
refreshProgressCounters,
|
||||||
@@ -15,6 +15,7 @@ import { useKeydown } from '../../hooks/use-keydown';
|
|||||||
import { isLoggedIn } from '../../lib/jwt';
|
import { isLoggedIn } from '../../lib/jwt';
|
||||||
import { useAuth } from '../../hooks/use-auth';
|
import { useAuth } from '../../hooks/use-auth';
|
||||||
import { useToast } from '../../hooks/use-toast';
|
import { useToast } from '../../hooks/use-toast';
|
||||||
|
import { DropdownIcon } from '../ReactIcons/DropdownIcon';
|
||||||
|
|
||||||
type TeamVersionsProps = {
|
type TeamVersionsProps = {
|
||||||
resourceId: string;
|
resourceId: string;
|
||||||
@@ -75,7 +76,7 @@ export function TeamVersions(props: TeamVersionsProps) {
|
|||||||
}/v1-get-team-versions?${new URLSearchParams({
|
}/v1-get-team-versions?${new URLSearchParams({
|
||||||
resourceId,
|
resourceId,
|
||||||
resourceType,
|
resourceType,
|
||||||
})}`
|
})}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (error || !response) {
|
if (error || !response) {
|
||||||
@@ -142,11 +143,7 @@ export function TeamVersions(props: TeamVersionsProps) {
|
|||||||
<span className="truncate">
|
<span className="truncate">
|
||||||
{selectedTeamVersion?.team.name || 'Team Versions'}
|
{selectedTeamVersion?.team.name || 'Team Versions'}
|
||||||
</span>
|
</span>
|
||||||
<img
|
<DropdownIcon className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
alt="Dropdown"
|
|
||||||
src={DropdownIcon.src}
|
|
||||||
className="h-3 w-3 sm:h-4 sm:w-4"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:hidden">
|
<div className="sm:hidden">
|
||||||
{shouldShowAvatar ? (
|
{shouldShowAvatar ? (
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import CloseIcon from '../../icons/close.svg';
|
|
||||||
import SpinnerIcon from '../../icons/spinner.svg';
|
|
||||||
|
|
||||||
import { useKeydown } from '../../hooks/use-keydown';
|
import { useKeydown } from '../../hooks/use-keydown';
|
||||||
import { useLoadTopic } from '../../hooks/use-load-topic';
|
import { useLoadTopic } from '../../hooks/use-load-topic';
|
||||||
@@ -26,8 +24,9 @@ import type {
|
|||||||
} from '../CustomRoadmap/CustomRoadmap';
|
} from '../CustomRoadmap/CustomRoadmap';
|
||||||
import { markdownToHtml } from '../../lib/markdown';
|
import { markdownToHtml } from '../../lib/markdown';
|
||||||
import { cn } from '../../lib/classname';
|
import { cn } from '../../lib/classname';
|
||||||
import { Ban, FileText } from 'lucide-react';
|
import { Ban, FileText, X } from 'lucide-react';
|
||||||
import { getUrlParams } from '../../lib/browser';
|
import { getUrlParams } from '../../lib/browser';
|
||||||
|
import { Spinner } from '../ReactIcons/Spinner';
|
||||||
|
|
||||||
type TopicDetailProps = {
|
type TopicDetailProps = {
|
||||||
canSubmitContribution: boolean;
|
canSubmitContribution: boolean;
|
||||||
@@ -203,10 +202,10 @@ export function TopicDetail(props: TopicDetailProps) {
|
|||||||
>
|
>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="flex w-full justify-center">
|
<div className="flex w-full justify-center">
|
||||||
<img
|
<Spinner
|
||||||
src={SpinnerIcon.src}
|
outerFill="#d1d5db"
|
||||||
alt="Loading"
|
className="h-6 w-6 sm:h-12 sm:w-12"
|
||||||
className="h-6 w-6 animate-spin fill-blue-600 text-gray-200 sm:h-12 sm:w-12"
|
innerFill="#2563eb"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -249,7 +248,7 @@ export function TopicDetail(props: TopicDetailProps) {
|
|||||||
setIsContributing(false);
|
setIsContributing(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img alt="Close" className="h-5 w-5" src={CloseIcon.src} />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -339,7 +338,7 @@ export function TopicDetail(props: TopicDetailProps) {
|
|||||||
setIsContributing(false);
|
setIsContributing(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img alt="Close" className="h-5 w-5" src={CloseIcon.src} />
|
<X className="h-5 w-5" />
|
||||||
</button>
|
</button>
|
||||||
<div className="flex h-full flex-col items-center justify-center">
|
<div className="flex h-full flex-col items-center justify-center">
|
||||||
<Ban className="h-16 w-16 text-red-500" />
|
<Ban className="h-16 w-16 text-red-500" />
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useKeydown } from '../../hooks/use-keydown';
|
import { useKeydown } from '../../hooks/use-keydown';
|
||||||
import { useOutsideClick } from '../../hooks/use-outside-click';
|
import { useOutsideClick } from '../../hooks/use-outside-click';
|
||||||
import DownIcon from '../../icons/down.svg';
|
|
||||||
import SpinnerIcon from '../../icons/spinner.svg';
|
|
||||||
import { isLoggedIn } from '../../lib/jwt';
|
import { isLoggedIn } from '../../lib/jwt';
|
||||||
import {
|
import {
|
||||||
getTopicStatus,
|
getTopicStatus,
|
||||||
@@ -10,9 +8,14 @@ import {
|
|||||||
renderTopicProgress,
|
renderTopicProgress,
|
||||||
updateResourceProgress,
|
updateResourceProgress,
|
||||||
} from '../../lib/resource-progress';
|
} from '../../lib/resource-progress';
|
||||||
import type { ResourceProgressType, ResourceType } from '../../lib/resource-progress';
|
import type {
|
||||||
|
ResourceProgressType,
|
||||||
|
ResourceType,
|
||||||
|
} from '../../lib/resource-progress';
|
||||||
import { showLoginPopup } from '../../lib/popup';
|
import { showLoginPopup } from '../../lib/popup';
|
||||||
import { useToast } from '../../hooks/use-toast';
|
import { useToast } from '../../hooks/use-toast';
|
||||||
|
import { Spinner } from '../ReactIcons/Spinner';
|
||||||
|
import { ChevronDown } from 'lucide-react';
|
||||||
|
|
||||||
type TopicProgressButtonProps = {
|
type TopicProgressButtonProps = {
|
||||||
topicId: string;
|
topicId: string;
|
||||||
@@ -27,7 +30,7 @@ const statusColors: Record<ResourceProgressType, string> = {
|
|||||||
learning: 'bg-yellow-500',
|
learning: 'bg-yellow-500',
|
||||||
pending: 'bg-gray-300',
|
pending: 'bg-gray-300',
|
||||||
skipped: 'bg-black',
|
skipped: 'bg-black',
|
||||||
removed: ''
|
removed: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TopicProgressButton(props: TopicProgressButtonProps) {
|
export function TopicProgressButton(props: TopicProgressButtonProps) {
|
||||||
@@ -71,7 +74,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
|
|
||||||
handleUpdateResourceProgress('done');
|
handleUpdateResourceProgress('done');
|
||||||
},
|
},
|
||||||
[progress]
|
[progress],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mark as learning
|
// Mark as learning
|
||||||
@@ -85,7 +88,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
|
|
||||||
handleUpdateResourceProgress('learning');
|
handleUpdateResourceProgress('learning');
|
||||||
},
|
},
|
||||||
[progress]
|
[progress],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mark as learning
|
// Mark as learning
|
||||||
@@ -99,7 +102,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
|
|
||||||
handleUpdateResourceProgress('skipped');
|
handleUpdateResourceProgress('skipped');
|
||||||
},
|
},
|
||||||
[progress]
|
[progress],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mark as pending
|
// Mark as pending
|
||||||
@@ -114,7 +117,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
|
|
||||||
handleUpdateResourceProgress('pending');
|
handleUpdateResourceProgress('pending');
|
||||||
},
|
},
|
||||||
[progress]
|
[progress],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleUpdateResourceProgress = (progress: ResourceProgressType) => {
|
const handleUpdateResourceProgress = (progress: ResourceProgressType) => {
|
||||||
@@ -131,7 +134,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
resourceId,
|
resourceId,
|
||||||
resourceType,
|
resourceType,
|
||||||
},
|
},
|
||||||
progress
|
progress,
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setProgress(progress);
|
setProgress(progress);
|
||||||
@@ -149,22 +152,22 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const allowMarkingSkipped = ['pending', 'learning', 'done'].includes(
|
const allowMarkingSkipped = ['pending', 'learning', 'done'].includes(
|
||||||
progress
|
progress,
|
||||||
);
|
);
|
||||||
const allowMarkingDone = ['skipped', 'pending', 'learning'].includes(
|
const allowMarkingDone = ['skipped', 'pending', 'learning'].includes(
|
||||||
progress
|
progress,
|
||||||
);
|
);
|
||||||
const allowMarkingLearning = ['done', 'skipped', 'pending'].includes(
|
const allowMarkingLearning = ['done', 'skipped', 'pending'].includes(
|
||||||
progress
|
progress,
|
||||||
);
|
);
|
||||||
const allowMarkingPending = ['skipped', 'done', 'learning'].includes(
|
const allowMarkingPending = ['skipped', 'done', 'learning'].includes(
|
||||||
progress
|
progress,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isUpdatingProgress) {
|
if (isUpdatingProgress) {
|
||||||
return (
|
return (
|
||||||
<button className="inline-flex cursor-default items-center rounded-md border border-gray-300 bg-white p-1 px-2 text-sm text-black">
|
<button className="inline-flex cursor-default items-center rounded-md border border-gray-300 bg-white p-1 px-2 text-sm text-black">
|
||||||
<img alt="Check" className="h-4 w-4 animate-spin" src={SpinnerIcon.src} />
|
<Spinner className="h-4 w-4" />
|
||||||
<span className="ml-2">Updating Status..</span>
|
<span className="ml-2">Updating Status..</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
@@ -188,7 +191,7 @@ export function TopicProgressButton(props: TopicProgressButtonProps) {
|
|||||||
onClick={() => setShowChangeStatus(true)}
|
onClick={() => setShowChangeStatus(true)}
|
||||||
>
|
>
|
||||||
<span className="mr-0.5">Update Status</span>
|
<span className="mr-0.5">Update Status</span>
|
||||||
<img alt="Check" className="h-4 w-4" src={DownIcon.src} />
|
<ChevronDown className="h-4 w-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showChangeStatus && (
|
{showChangeStatus && (
|
||||||
|
Reference in New Issue
Block a user