- {!isLoading && progress?.length == 0 &&
}
- {hasProgress && (
-
+
+ {resourceTitle}
+
+
+
+
+ {allowFavorite && (
+
+ )}
+
+ );
+}
+
+type HeroTitleProps = {
+ icon: any;
+ isLoading?: boolean;
+ title: string | ReactNode;
+};
+
+function HeroTitle(props: HeroTitleProps) {
+ const { isLoading = false, title, icon } = props;
+
+ return (
+
+ {!isLoading && icon}
+ {isLoading && (
+
+
+
+ )}
+ {title}
+
+ );
+}
+
+type FavoriteRoadmapsProps = {
+ progress: UserProgress[];
+ projects: (ProjectStatusDocument & {
+ title: string;
+ })[];
+ customRoadmaps: UserProgress[];
+ aiRoadmaps: AIRoadmapType[];
+ isLoading: boolean;
+};
+
+type HeroProjectProps = {
+ project: ProjectStatusDocument & {
+ title: string;
+ };
+};
+
+export function HeroProject({ project }: HeroProjectProps) {
+ return (
+
+
+
+ {project.title}
+
+
+ {project.submittedAt && project.repositoryUrl
+ ? 'Submitted'
+ : 'In Progress'}
+
+
+
+
+
+ {project.upvotes}
+
+ {project.startedAt && (
+ Started {getRelativeTimeString(project.startedAt)}
+ )}
+
+
+
+ {project.submittedAt && project.repositoryUrl && (
+
+ )}
+
+ );
+}
+
+export function FavoriteRoadmaps(props: FavoriteRoadmapsProps) {
+ const { progress, isLoading, customRoadmaps, aiRoadmaps, projects } = props;
+
+ return (
+
+
+
+
+ ) as any
+ }
+ isLoading={isLoading}
+ title="Your progress and bookmarks"
+ />
+ {!isLoading && progress.length > 0 && (
+
+ {progress.map((resource) => (
+
+ ))}
+
+
+ )}
+
+
+
+
+
+
) as any}
+ isLoading={isLoading}
+ title="Your custom roadmaps"
+ />
+ {!isLoading && customRoadmaps.length > 0 && (
+
+ {customRoadmaps.map((customRoadmap) => (
+
+ ))}
+
+
+ )}
+
+
+
+
+
+
) as any}
+ isLoading={isLoading}
+ title="Your AI roadmaps"
+ />
+ {!isLoading && aiRoadmaps.length > 0 && (
+
+ )}
+
+
+
+
+
+
) as any
+ }
+ isLoading={isLoading}
+ title="Your projects"
+ />
+ {!isLoading && projects.length > 0 && (
+
)}
diff --git a/src/components/HeroSection/HeroRoadmaps.tsx b/src/components/HeroSection/HeroRoadmaps.tsx
deleted file mode 100644
index 7633f0ab7..000000000
--- a/src/components/HeroSection/HeroRoadmaps.tsx
+++ /dev/null
@@ -1,264 +0,0 @@
-import type { UserProgressResponse } from './FavoriteRoadmaps';
-import { CheckIcon } from '../ReactIcons/CheckIcon';
-import { MarkFavorite } from '../FeaturedItems/MarkFavorite';
-import { Spinner } from '../ReactIcons/Spinner';
-import type { ResourceType } from '../../lib/resource-progress';
-import { MapIcon, Users2 } from 'lucide-react';
-import { CreateRoadmapButton } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapButton';
-import { CreateRoadmapModal } from '../CustomRoadmap/CreateRoadmap/CreateRoadmapModal';
-import { type ReactNode, useState } from 'react';
-import { FeatureAnnouncement } from '../FeatureAnnouncement.tsx';
-
-type ProgressRoadmapProps = {
- url: string;
- percentageDone: number;
- allowFavorite?: boolean;
-
- resourceId: string;
- resourceType: ResourceType;
- resourceTitle: string;
- isFavorite?: boolean;
-};
-function HeroRoadmap(props: ProgressRoadmapProps) {
- const {
- url,
- percentageDone,
- resourceType,
- resourceId,
- resourceTitle,
- isFavorite,
- allowFavorite = true,
- } = props;
-
- return (
-
- {resourceTitle}
-
-
-
- {allowFavorite && (
-
- )}
-
- );
-}
-
-type ProgressTitleProps = {
- icon: any;
- isLoading?: boolean;
- title: string | ReactNode;
-};
-
-export function HeroTitle(props: ProgressTitleProps) {
- const { isLoading = false, title, icon } = props;
-
- return (
-
- {!isLoading && icon}
- {isLoading && (
-
-
-
- )}
- {title}
-
- );
-}
-export type HeroTeamRoadmaps = Record
;
-
-type ProgressListProps = {
- progress: UserProgressResponse;
- customRoadmaps: UserProgressResponse;
- teamRoadmaps?: HeroTeamRoadmaps;
- isLoading?: boolean;
-};
-
-export function HeroRoadmaps(props: ProgressListProps) {
- const {
- teamRoadmaps = {},
- progress,
- isLoading = false,
- customRoadmaps,
- } = props;
-
- const [isCreatingRoadmap, setIsCreatingRoadmap] = useState(false);
- const [creatingRoadmapTeamId, setCreatingRoadmapTeamId] = useState();
-
- return (
-
-
-
-
- {isCreatingRoadmap && (
-
{
- setIsCreatingRoadmap(false);
- setCreatingRoadmapTeamId(undefined);
- }}
- />
- )}
- {
- ) as any
- }
- isLoading={isLoading}
- title="Your progress and favorite roadmaps."
- />
- }
-
-
- {progress.map((resource) => (
-
- ))}
-
-
-
- {
-
}
- title="Your custom roadmaps"
- />
- }
-
- {customRoadmaps.length === 0 && (
-
- You haven't created any custom roadmaps yet.{' '}
-
-
- )}
-
- {customRoadmaps.length > 0 && (
-
- {customRoadmaps.map((customRoadmap) => {
- return (
-
- );
- })}
-
-
-
- )}
-
-
- {Object.keys(teamRoadmaps).map((teamName) => {
- const currentTeam: UserProgressResponse[0]['team'] =
- teamRoadmaps?.[teamName]?.[0]?.team;
- const roadmapsList = teamRoadmaps[teamName].filter(
- (roadmap) => !!roadmap.resourceTitle,
- );
- const canManageTeam = ['admin', 'manager'].includes(currentTeam?.role!);
-
- return (
-
- {
-
}
- title={
- <>
- Team{' '}
-
- {teamName}
-
- Roadmaps
- >
- }
- />
- }
-
- {roadmapsList.length === 0 && (
-
- Team does not have any roadmaps yet.{' '}
- {canManageTeam && (
-
- )}
-
- )}
-
- {roadmapsList.length > 0 && (
-
- {roadmapsList.map((customRoadmap) => {
- return (
-
- );
- })}
-
- {canManageTeam && (
-
- )}
-
- )}
-
- );
- })}
-
- );
-}
diff --git a/src/components/RoadCard/RoadmapSelect.tsx b/src/components/RoadCard/RoadmapSelect.tsx
index 2db7bc2e4..baa7fae22 100644
--- a/src/components/RoadCard/RoadmapSelect.tsx
+++ b/src/components/RoadCard/RoadmapSelect.tsx
@@ -1,8 +1,8 @@
import { httpGet } from '../../lib/http';
import { useEffect, useState } from 'react';
import { pageProgressMessage } from '../../stores/page';
-import type { UserProgressResponse } from '../HeroSection/FavoriteRoadmaps';
import { SelectionButton } from './SelectionButton';
+import type { UserProgressResponse } from '../Roadmaps/RoadmapsPage';
type RoadmapSelectProps = {
selectedRoadmaps: string[];
diff --git a/src/components/Roadmaps/RoadmapsPage.tsx b/src/components/Roadmaps/RoadmapsPage.tsx
index defe3e3e8..91b6a72e1 100644
--- a/src/components/Roadmaps/RoadmapsPage.tsx
+++ b/src/components/Roadmaps/RoadmapsPage.tsx
@@ -10,8 +10,27 @@ import {
} from '../../lib/browser.ts';
import { RoadmapCard } from './RoadmapCard.tsx';
import { httpGet } from '../../lib/http.ts';
-import type { UserProgressResponse } from '../HeroSection/FavoriteRoadmaps.tsx';
import { isLoggedIn } from '../../lib/jwt.ts';
+import type { AllowedMemberRoles } from '../ShareOptions/ShareTeamMemberList.tsx';
+
+export type UserProgressResponse = {
+ resourceId: string;
+ resourceType: 'roadmap' | 'best-practice';
+ resourceTitle: string;
+ isFavorite: boolean;
+ done: number;
+ learning: number;
+ skipped: number;
+ total: number;
+ updatedAt: Date;
+ isCustomResource: boolean;
+ roadmapSlug?: string;
+ team?: {
+ name: string;
+ id: string;
+ role: AllowedMemberRoles;
+ };
+}[];
const groupNames = [
'Absolute Beginners',
diff --git a/src/components/TeamProgress/TeamProgressPage.tsx b/src/components/TeamProgress/TeamProgressPage.tsx
index 78e8c7585..74784f959 100644
--- a/src/components/TeamProgress/TeamProgressPage.tsx
+++ b/src/components/TeamProgress/TeamProgressPage.tsx
@@ -1,16 +1,15 @@
+import { useStore } from '@nanostores/react';
import { useEffect, useState } from 'react';
+import { useAuth } from '../../hooks/use-auth';
+import { useToast } from '../../hooks/use-toast';
+import { getUrlParams, setUrlParams } from '../../lib/browser';
import { httpGet } from '../../lib/http';
import { pageProgressMessage } from '../../stores/page';
-import { MemberProgressItem } from './MemberProgressItem';
-import { useToast } from '../../hooks/use-toast';
-import { useStore } from '@nanostores/react';
import { $currentTeam } from '../../stores/team';
import { GroupRoadmapItem } from './GroupRoadmapItem';
-import { getUrlParams, setUrlParams } from '../../lib/browser';
-import { useAuth } from '../../hooks/use-auth';
-import { MemberProgressModal } from './MemberProgressModal';
import { MemberCustomProgressModal } from './MemberCustomProgressModal';
-import { canManageCurrentRoadmap } from '../../stores/roadmap.ts';
+import { MemberProgressItem } from './MemberProgressItem';
+import { MemberProgressModal } from './MemberProgressModal';
export type UserProgress = {
resourceTitle: string;
diff --git a/src/pages/dashboard.astro b/src/pages/dashboard.astro
index 50d8afcce..ec1d3d81c 100644
--- a/src/pages/dashboard.astro
+++ b/src/pages/dashboard.astro
@@ -56,7 +56,7 @@ const enrichedBestPractices = bestPractices.map((bestPractice) => {
});
---
-
+
{
client:load
/>
-
+
diff --git a/src/styles/global.css b/src/styles/global.css
index ab2e901cb..c3738d341 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -128,8 +128,20 @@ a > code:before {
animation: barberpole 15s linear infinite;
}
+.striped-loader-slate {
+ background-image: repeating-linear-gradient(
+ -45deg,
+ transparent,
+ transparent 5px,
+ hsla(0, 0%, 0%, 0.1) 5px,
+ hsla(0, 0%, 0%, 0.1) 10px
+ );
+ background-size: 200% 200%;
+ animation: barberpole 30s linear infinite;
+}
+
@keyframes barberpole {
100% {
background-position: 100% 100%;
}
-}
\ No newline at end of file
+}