mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-16 14:14:11 +02:00
Add progress loading on homepage roadmaps
This commit is contained in:
@@ -13,14 +13,14 @@ const { isUpcoming = false, isNew = false, text, url } = Astro.props;
|
|||||||
|
|
||||||
<a
|
<a
|
||||||
class:list={[
|
class:list={[
|
||||||
'group border border-slate-800 bg-slate-900 p-2.5 sm:p-3.5 block no-underline rounded-lg relative text-slate-400 font-regular text-md hover:border-slate-600 hover:text-slate-100',
|
'group border border-slate-800 bg-slate-900 p-2.5 sm:p-3.5 block no-underline rounded-lg relative text-slate-400 font-regular text-md hover:border-slate-600 hover:text-slate-100 overflow-hidden',
|
||||||
{
|
{
|
||||||
'opacity-50': isUpcoming,
|
'opacity-50': isUpcoming,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
href={url}
|
href={url}
|
||||||
>
|
>
|
||||||
<span class='text-slate-400'>
|
<span class='text-slate-400 relative z-20'>
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
@@ -5,7 +5,11 @@ import AccountDropdown from './AccountDropdown.astro';
|
|||||||
|
|
||||||
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
||||||
<nav class='container flex items-center justify-between'>
|
<nav class='container flex items-center justify-between'>
|
||||||
<a class='flex items-center text-lg font-medium text-white' href='/' aria-label="roadmap.sh">
|
<a
|
||||||
|
class='flex items-center text-lg font-medium text-white'
|
||||||
|
href='/'
|
||||||
|
aria-label='roadmap.sh'
|
||||||
|
>
|
||||||
<Icon icon='logo' />
|
<Icon icon='logo' />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@@ -26,9 +30,12 @@ import AccountDropdown from './AccountDropdown.astro';
|
|||||||
<a href='/videos' class='text-gray-400 hover:text-white'>Videos</a>
|
<a href='/videos' class='text-gray-400 hover:text-white'>Videos</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<kbd data-command-menu class="hidden sm:flex items-center text-gray-400 border border-gray-800 rounded-md px-2.5 py-1 text-sm hover:bg-gray-800 hover:cursor-pointer">
|
<kbd
|
||||||
<Icon icon='search' class='h-3 w-3 mr-2' />
|
data-command-menu
|
||||||
<kbd class='font-sans mr-1'>⌘</kbd><kbd class='font-sans'>K</kbd>
|
class='hidden items-center rounded-md border border-gray-800 px-2.5 py-1 text-sm text-gray-400 hover:cursor-pointer hover:bg-gray-800 sm:flex'
|
||||||
|
>
|
||||||
|
<Icon icon='search' class='mr-2 h-3 w-3' />
|
||||||
|
<kbd class='mr-1 font-sans'>⌘</kbd><kbd class='font-sans'>K</kbd>
|
||||||
</kbd>
|
</kbd>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -97,10 +104,7 @@ import AccountDropdown from './AccountDropdown.astro';
|
|||||||
|
|
||||||
<!-- Links for logged in users -->
|
<!-- Links for logged in users -->
|
||||||
<li data-auth-required class='hidden'>
|
<li data-auth-required class='hidden'>
|
||||||
<a
|
<a href='/account' class='text-xl hover:text-blue-300 md:text-lg'>
|
||||||
href='/account'
|
|
||||||
class='text-xl hover:text-blue-300 md:text-lg'
|
|
||||||
>
|
|
||||||
Account
|
Account
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@@ -149,8 +149,8 @@ const gaPageIdentifier = Astro.url.pathname
|
|||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<Authenticator />
|
<Authenticator />
|
||||||
<PageProgress initialMessage={initialLoadingMessage} client:idle />
|
|
||||||
<CommandMenu client:idle />
|
<CommandMenu client:idle />
|
||||||
|
<PageProgress initialMessage={initialLoadingMessage} client:idle />
|
||||||
<PageSponsor
|
<PageSponsor
|
||||||
gaPageIdentifier={briefTitle || gaPageIdentifier}
|
gaPageIdentifier={briefTitle || gaPageIdentifier}
|
||||||
client:load
|
client:load
|
||||||
|
57
src/lib/home-progress.ts
Normal file
57
src/lib/home-progress.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { httpGet } from './http';
|
||||||
|
import { isLoggedIn } from './jwt';
|
||||||
|
|
||||||
|
type UserProgressResponse = {
|
||||||
|
resourceId: string;
|
||||||
|
resourceType: 'roadmap' | 'best-practice';
|
||||||
|
done: number;
|
||||||
|
learning: number;
|
||||||
|
skipped: number;
|
||||||
|
total: number;
|
||||||
|
updatedAt: Date;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
async function renderProgress() {
|
||||||
|
if (!isLoggedIn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { response: progressList, error } = await httpGet<UserProgressResponse>(
|
||||||
|
`${import.meta.env.PUBLIC_API_URL}/v1-get-user-all-progress`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (error || !progressList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
progressList.forEach((progress) => {
|
||||||
|
const href =
|
||||||
|
progress.resourceType === 'best-practice'
|
||||||
|
? `/best-practices/${progress.resourceId}`
|
||||||
|
: `/${progress.resourceId}`;
|
||||||
|
const element = document.querySelector(`a[href="${href}"]`);
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalDone = progress.done + progress.skipped;
|
||||||
|
const percentageDone = (totalDone / progress.total) * 100;
|
||||||
|
|
||||||
|
const progressBar = document.createElement('div');
|
||||||
|
progressBar.style.backgroundColor = 'rgb(23 42 58)';
|
||||||
|
progressBar.style.position = 'absolute';
|
||||||
|
progressBar.style.width = `${percentageDone}%`;
|
||||||
|
progressBar.style.height = '100%';
|
||||||
|
progressBar.style.bottom = '0';
|
||||||
|
progressBar.style.left = '0';
|
||||||
|
progressBar.style.top = '0';
|
||||||
|
progressBar.style.zIndex = '1';
|
||||||
|
|
||||||
|
element.appendChild(progressBar);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// on DOM load
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
window.setTimeout(renderProgress, 0);
|
||||||
|
});
|
@@ -8,7 +8,7 @@ const legacyRoadmapUrls = [...roadmapIds.map((id) => `/${id}/`), '/roadmaps/'];
|
|||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout title='Page not found' permalink={'/404'} noIndex={true}>
|
<BaseLayout title='Page not found' permalink={'/404'} noIndex={true}>
|
||||||
<!-- Legacy roadmp pages handling -->
|
<!-- Legacy roadmap pages handling -->
|
||||||
<script slot='after-header' define:vars={{ legacyRoadmapUrls }}>
|
<script slot='after-header' define:vars={{ legacyRoadmapUrls }}>
|
||||||
// If it's a roadmap page and it ends with a slash
|
// If it's a roadmap page and it ends with a slash
|
||||||
// redirect to the same page without the slash
|
// redirect to the same page without the slash
|
||||||
|
@@ -23,20 +23,24 @@ const videos = await getAllVideos();
|
|||||||
>
|
>
|
||||||
<div class='bg-gradient-to-b from-slate-900 to-black'>
|
<div class='bg-gradient-to-b from-slate-900 to-black'>
|
||||||
<div class='border-b border-b-[#1e293c]'>
|
<div class='border-b border-b-[#1e293c]'>
|
||||||
<div class='container text-left sm:text-center py-6 pb-14 sm:py-20 px-6 sm:px-0'>
|
<div
|
||||||
|
class='container px-6 py-6 pb-14 text-left sm:px-0 sm:py-20 sm:text-center'
|
||||||
|
>
|
||||||
<h1
|
<h1
|
||||||
class='text-2xl sm:text-5xl mb-2 sm:mb-4 font-bold bg-gradient-to-b from-amber-50 to-purple-500 text-transparent bg-clip-text'
|
class='mb-2 bg-gradient-to-b from-amber-50 to-purple-500 bg-clip-text text-2xl font-bold text-transparent sm:mb-4 sm:text-5xl'
|
||||||
>
|
>
|
||||||
Developer Roadmaps
|
Developer Roadmaps
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class='hidden sm:block text-gray-400 text-lg px-4'>
|
<p class='hidden px-4 text-lg text-gray-400 sm:block'>
|
||||||
<span class='font-medium text-gray-400'>roadmap.sh</span> is a community effort to create roadmaps, guides and
|
<span class='font-medium text-gray-400'>roadmap.sh</span> is a community
|
||||||
other educational content to help guide developers in picking up the path and guide their learnings.
|
effort to create roadmaps, guides and other educational content to help
|
||||||
|
guide developers in picking up the path and guide their learnings.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class='block sm:hidden text-gray-400 text-md px-0'>
|
<p class='text-md block px-0 text-gray-400 sm:hidden'>
|
||||||
Community created roadmaps, guides and articles to help developers grow in their career.
|
Community created roadmaps, guides and articles to help developers
|
||||||
|
grow in their career.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,7 +58,10 @@ const videos = await getAllVideos();
|
|||||||
<FeaturedItems
|
<FeaturedItems
|
||||||
heading='Skill based Roadmaps'
|
heading='Skill based Roadmaps'
|
||||||
featuredItems={skillRoadmaps.map((roadmapItem) => ({
|
featuredItems={skillRoadmaps.map((roadmapItem) => ({
|
||||||
text: roadmapItem.frontmatter.briefTitle === 'Go' ? 'Go Roadmap' : roadmapItem.frontmatter.briefTitle,
|
text:
|
||||||
|
roadmapItem.frontmatter.briefTitle === 'Go'
|
||||||
|
? 'Go Roadmap'
|
||||||
|
: roadmapItem.frontmatter.briefTitle,
|
||||||
url: `/${roadmapItem.id}`,
|
url: `/${roadmapItem.id}`,
|
||||||
isNew: roadmapItem.frontmatter.isNew,
|
isNew: roadmapItem.frontmatter.isNew,
|
||||||
isUpcoming: roadmapItem.frontmatter.isUpcoming,
|
isUpcoming: roadmapItem.frontmatter.isUpcoming,
|
||||||
@@ -71,9 +78,11 @@ const videos = await getAllVideos();
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class='grid grid-cols-1 gap-7 sm:gap-16 bg-gray-50 py-7 sm:py-16'>
|
<div class='grid grid-cols-1 gap-7 bg-gray-50 py-7 sm:gap-16 sm:py-16'>
|
||||||
<FeaturedGuides heading='Guides' guides={guides.slice(0, 7)} />
|
<FeaturedGuides heading='Guides' guides={guides.slice(0, 7)} />
|
||||||
<FeaturedVideos heading='Videos' videos={videos.slice(0, 7)} />
|
<FeaturedVideos heading='Videos' videos={videos.slice(0, 7)} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src='../lib/home-progress.ts'></script>
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
|
Reference in New Issue
Block a user