mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-03-15 12:49:43 +01:00
Add progress loading on homepage roadmaps
This commit is contained in:
parent
502b8e20d5
commit
43f351a943
@ -13,14 +13,14 @@ const { isUpcoming = false, isNew = false, text, url } = Astro.props;
|
||||
|
||||
<a
|
||||
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,
|
||||
},
|
||||
]}
|
||||
href={url}
|
||||
>
|
||||
<span class='text-slate-400'>
|
||||
<span class='text-slate-400 relative z-20'>
|
||||
{text}
|
||||
</span>
|
||||
|
||||
|
@ -5,7 +5,11 @@ import AccountDropdown from './AccountDropdown.astro';
|
||||
|
||||
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
||||
<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' />
|
||||
</a>
|
||||
|
||||
@ -26,9 +30,12 @@ import AccountDropdown from './AccountDropdown.astro';
|
||||
<a href='/videos' class='text-gray-400 hover:text-white'>Videos</a>
|
||||
</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">
|
||||
<Icon icon='search' class='h-3 w-3 mr-2' />
|
||||
<kbd class='font-sans mr-1'>⌘</kbd><kbd class='font-sans'>K</kbd>
|
||||
<kbd
|
||||
data-command-menu
|
||||
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>
|
||||
</li>
|
||||
</ul>
|
||||
@ -97,10 +104,7 @@ import AccountDropdown from './AccountDropdown.astro';
|
||||
|
||||
<!-- Links for logged in users -->
|
||||
<li data-auth-required class='hidden'>
|
||||
<a
|
||||
href='/account'
|
||||
class='text-xl hover:text-blue-300 md:text-lg'
|
||||
>
|
||||
<a href='/account' class='text-xl hover:text-blue-300 md:text-lg'>
|
||||
Account
|
||||
</a>
|
||||
</li>
|
||||
|
@ -149,8 +149,8 @@ const gaPageIdentifier = Astro.url.pathname
|
||||
</slot>
|
||||
|
||||
<Authenticator />
|
||||
<PageProgress initialMessage={initialLoadingMessage} client:idle />
|
||||
<CommandMenu client:idle />
|
||||
<PageProgress initialMessage={initialLoadingMessage} client:idle />
|
||||
<PageSponsor
|
||||
gaPageIdentifier={briefTitle || gaPageIdentifier}
|
||||
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}>
|
||||
<!-- Legacy roadmp pages handling -->
|
||||
<!-- Legacy roadmap pages handling -->
|
||||
<script slot='after-header' define:vars={{ legacyRoadmapUrls }}>
|
||||
// If it's a roadmap page and it ends with a 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='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
|
||||
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
|
||||
</h1>
|
||||
|
||||
<p class='hidden sm:block text-gray-400 text-lg px-4'>
|
||||
<span class='font-medium text-gray-400'>roadmap.sh</span> is a community effort to create roadmaps, guides and
|
||||
other educational content to help guide developers in picking up the path and guide their learnings.
|
||||
<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 other educational content to help
|
||||
guide developers in picking up the path and guide their learnings.
|
||||
</p>
|
||||
|
||||
<p class='block sm:hidden text-gray-400 text-md px-0'>
|
||||
Community created roadmaps, guides and articles to help developers grow in their career.
|
||||
<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.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -54,7 +58,10 @@ const videos = await getAllVideos();
|
||||
<FeaturedItems
|
||||
heading='Skill based Roadmaps'
|
||||
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}`,
|
||||
isNew: roadmapItem.frontmatter.isNew,
|
||||
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)} />
|
||||
<FeaturedVideos heading='Videos' videos={videos.slice(0, 7)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src='../lib/home-progress.ts'></script>
|
||||
</BaseLayout>
|
||||
|
Loading…
x
Reference in New Issue
Block a user