diff --git a/src/components/ReactIcons/HackerNewsIcon.tsx b/src/components/ReactIcons/HackerNewsIcon.tsx new file mode 100644 index 000000000..bd2994df2 --- /dev/null +++ b/src/components/ReactIcons/HackerNewsIcon.tsx @@ -0,0 +1,20 @@ +import { cn } from '../../lib/classname'; + +interface HackerNewsIconProps { + className?: string; +} + +export function HackerNewsIcon(props: HackerNewsIconProps) { + const { className } = props; + + return ( + + + + ); +} diff --git a/src/components/ReactIcons/RedditIcon.tsx b/src/components/ReactIcons/RedditIcon.tsx new file mode 100644 index 000000000..506615454 --- /dev/null +++ b/src/components/ReactIcons/RedditIcon.tsx @@ -0,0 +1,20 @@ +import { cn } from '../../lib/classname'; + +interface RedditIconProps { + className?: string; +} + +export function RedditIcon(props: RedditIconProps) { + const { className } = props; + + return ( + + + + ); +} diff --git a/src/components/ReactIcons/TwitterIcon.tsx b/src/components/ReactIcons/TwitterIcon.tsx index 05e6a5683..bb8c1f3d6 100644 --- a/src/components/ReactIcons/TwitterIcon.tsx +++ b/src/components/ReactIcons/TwitterIcon.tsx @@ -18,7 +18,7 @@ export function TwitterIcon(props: TwitterIconProps) { ); diff --git a/src/components/ShareIcons/ShareIcons.astro b/src/components/ShareIcons/ShareIcons.astro deleted file mode 100644 index 2fa224972..000000000 --- a/src/components/ShareIcons/ShareIcons.astro +++ /dev/null @@ -1,34 +0,0 @@ ---- -import Icon from '../AstroIcon.astro'; - -export interface Props { - pageUrl: string; - description: string; -} - -const { pageUrl, description } = Astro.props; - -const twitterUrl = `https://twitter.com/intent/tweet?text=${description}&url=${pageUrl}`; -const fbUrl = `https://www.facebook.com/sharer/sharer.php?quote=${description}&u=${pageUrl}`; -const hnUrl = `https://news.ycombinator.com/submitlink?t=${description}&u=${pageUrl}`; -const redditUrl = `https://www.reddit.com/submit?title=${description}&url=${pageUrl}`; ---- - - - - diff --git a/src/components/ShareIcons/ShareIcons.tsx b/src/components/ShareIcons/ShareIcons.tsx new file mode 100644 index 000000000..09ce80589 --- /dev/null +++ b/src/components/ShareIcons/ShareIcons.tsx @@ -0,0 +1,99 @@ +import { useEffect, useRef } from 'react'; +import { cn } from '../../lib/classname'; +import { FacebookIcon } from '../ReactIcons/FacebookIcon'; +import { HackerNewsIcon } from '../ReactIcons/HackerNewsIcon'; +import { RedditIcon } from '../ReactIcons/RedditIcon'; +import { TwitterIcon } from '../ReactIcons/TwitterIcon'; + +type ShareIconsProps = { + pageUrl: string; + description: string; +}; + +export function ShareIcons(props: ShareIconsProps) { + const { pageUrl, description } = props; + + const shareIconsRef = useRef(null); + + const twitterUrl = `https://twitter.com/intent/tweet?text=${description}&url=${pageUrl}`; + const fbUrl = `https://www.facebook.com/sharer/sharer.php?quote=${description}&u=${pageUrl}`; + const hnUrl = `https://news.ycombinator.com/submitlink?t=${description}&u=${pageUrl}`; + const redditUrl = `https://www.reddit.com/submit?title=${description}&url=${pageUrl}`; + + const icons = [ + { + url: twitterUrl, + icon: ( + + ), + }, + { + url: fbUrl, + icon: , + }, + { + url: hnUrl, + icon: , + }, + { + url: redditUrl, + icon: , + }, + ]; + + useEffect(() => { + const shareIcons = shareIconsRef.current; + if (!shareIcons) { + return; + } + + const onScroll = () => { + if (window.scrollY < 100 || window.innerWidth < 1050) { + shareIcons.classList.add('hidden'); + return null; + } + + shareIcons.classList.remove('hidden'); + }; + + onScroll(); + + window.addEventListener('scroll', onScroll); + return () => { + window.removeEventListener('scroll', onScroll); + }; + }, []); + + return ( + + ); +} diff --git a/src/components/ShareIcons/sharer.js b/src/components/ShareIcons/sharer.js deleted file mode 100644 index 8bb12ca76..000000000 --- a/src/components/ShareIcons/sharer.js +++ /dev/null @@ -1,32 +0,0 @@ -export class Sharer { - constructor() { - this.init = this.init.bind(this); - this.onScroll = this.onScroll.bind(this); - - this.shareIconsId = 'page-share-icons'; - } - - get shareIconsEl() { - return document.getElementById(this.shareIconsId); - } - - onScroll() { - if (window.scrollY < 100 || window.innerWidth < 1050) { - this.shareIconsEl.classList.add('hidden'); - return null; - } - - this.shareIconsEl.classList.remove('hidden'); - } - - init() { - if (!this.shareIconsEl) { - return; - } - - window.addEventListener('scroll', this.onScroll, { passive: true }); - } -} - -const sharer = new Sharer(); -sharer.init(); diff --git a/src/pages/[roadmapId]/courses.astro b/src/pages/[roadmapId]/courses.astro index d7a606f85..f344a624d 100644 --- a/src/pages/[roadmapId]/courses.astro +++ b/src/pages/[roadmapId]/courses.astro @@ -1,25 +1,8 @@ --- -import { EditorRoadmap } from '../../components/EditorRoadmap/EditorRoadmap'; -import FAQs, { type FAQType } from '../../components/FAQs/FAQs.astro'; -import FrameRenderer from '../../components/FrameRenderer/FrameRenderer.astro'; -import RelatedRoadmaps from '../../components/RelatedRoadmaps.astro'; import RoadmapHeader from '../../components/RoadmapHeader.astro'; -import { FolderKanbanIcon } from 'lucide-react'; -import { EmptyProjects } from '../../components/Projects/EmptyProjects'; -import ShareIcons from '../../components/ShareIcons/ShareIcons.astro'; -import { UserProgressModal } from '../../components/UserProgress/UserProgressModal'; import BaseLayout from '../../layouts/BaseLayout.astro'; -import { getProjectsByRoadmapId } from '../../lib/project'; -import { - generateArticleSchema, - generateFAQSchema, -} from '../../lib/jsonld-schema'; import { getOpenGraphImageUrl } from '../../lib/open-graph'; import { type RoadmapFrontmatter, getRoadmapIds } from '../../lib/roadmap'; -import RoadmapNote from '../../components/RoadmapNote.astro'; -import { RoadmapTitleQuestion } from '../../components/RoadmapTitleQuestion'; -import ResourceProgressStats from '../../components/ResourceProgressStats.astro'; -import AstroIcon from '../../components/AstroIcon.astro'; import CourseStep from '../../components/courses/CourseStep.astro'; import Milestone from '../../components/courses/Milestone.astro'; @@ -95,24 +78,42 @@ const seoDescription = `Seeking ${nounTitle.toLowerCase()} courses to enhance yo
-
+

Frontend development is a vast field with a lot of tools and - technologies. We have the frontend roadmap - which is filled with a lot of free and good resources to help you learn. But sometimes it helps to have a minimalistic list of courses - and project recommendations to help you get started. + technologies. We have the frontend roadmap + which is filled with a lot of free and good resources to help you learn. But sometimes it helps to have a minimalistic + list of courses and project recommendations to help you get started.

-

- Below are some of the best courses (paid) and projects to help you learn frontend development. These are handpicked and are a great way to get started. +

+ Below are some of the best courses (paid) and projects to help you + learn frontend development. These are handpicked and are a great way + to get started.

- Please note that these are paid courses curated from external platforms. We earn a small commission if you purchase the course using the links below. This helps us maintain the website and keep it free for everyone. + Please note that these are paid courses curated from external + platforms. We earn a small commission if you purchase the course + using the links below. This helps us maintain the website and keep + it free for everyone.

- If you are looking for free resources, you can check out the frontend roadmap. Also, we have a list of projects that you can work on to enhance your skills. + If you are looking for free resources, you can check out the frontend roadmap. Also, we have a list of projects that you can work on to enhance your skills.

diff --git a/src/pages/[roadmapId]/index.astro b/src/pages/[roadmapId]/index.astro index 524508bcb..779e89430 100644 --- a/src/pages/[roadmapId]/index.astro +++ b/src/pages/[roadmapId]/index.astro @@ -4,7 +4,7 @@ import FAQs, { type FAQType } from '../../components/FAQs/FAQs.astro'; import FrameRenderer from '../../components/FrameRenderer/FrameRenderer.astro'; import RelatedRoadmaps from '../../components/RelatedRoadmaps.astro'; import RoadmapHeader from '../../components/RoadmapHeader.astro'; -import ShareIcons from '../../components/ShareIcons/ShareIcons.astro'; +import { ShareIcons } from '../../components/ShareIcons/ShareIcons'; import { TopicDetail } from '../../components/TopicDetail/TopicDetail'; import { UserProgressModal } from '../../components/UserProgress/UserProgressModal'; import BaseLayout from '../../layouts/BaseLayout.astro'; @@ -136,6 +136,7 @@ const projects = await getProjectsByRoadmapId(roadmapId); { diff --git a/src/pages/best-practices/[bestPracticeId]/index.astro b/src/pages/best-practices/[bestPracticeId]/index.astro index b4f40fb44..c47a49acf 100644 --- a/src/pages/best-practices/[bestPracticeId]/index.astro +++ b/src/pages/best-practices/[bestPracticeId]/index.astro @@ -2,7 +2,7 @@ import BestPracticeHeader from '../../../components/BestPracticeHeader.astro'; import FrameRenderer from '../../../components/FrameRenderer/FrameRenderer.astro'; import MarkdownFile from '../../../components/MarkdownFile.astro'; -import ShareIcons from '../../../components/ShareIcons/ShareIcons.astro'; +import { ShareIcons } from '../../../components/ShareIcons/ShareIcons'; import { TopicDetail } from '../../../components/TopicDetail/TopicDetail'; import UpcomingForm from '../../../components/UpcomingForm.astro'; import BaseLayout from '../../../layouts/BaseLayout.astro'; @@ -96,6 +96,7 @@ const ogImageUrl = getOpenGraphImageUrl({