diff --git a/src/components/CommandMenu/CommandMenu.tsx b/src/components/CommandMenu/CommandMenu.tsx index 7aab90e5b..822967dbb 100644 --- a/src/components/CommandMenu/CommandMenu.tsx +++ b/src/components/CommandMenu/CommandMenu.tsx @@ -1,19 +1,62 @@ -import { useState } from 'preact/hooks'; +import { useEffect, useState } from 'preact/hooks'; +import { httpGet } from '../../lib/http'; -const defaultPages = [ - { href: '/profile', title: 'Account', group: 'Pages' }, - { href: '/roadmaps', title: 'Roadmaps', group: 'Pages' }, - { href: '/best-practices', title: 'Best Practices', group: 'Pages' }, - { href: '/guides', title: 'Guides', group: 'Pages' }, - { href: '/videos', title: 'Videos', group: 'Pages' }, +type PageType = { + url: string; + title: string; + group: string; +}; + +const defaultPages: PageType[] = [ + { url: '/', title: 'Home', group: 'Pages' }, + { url: '/profile', title: 'Account', group: 'Pages' }, + { url: '/roadmaps', title: 'Roadmaps', group: 'Pages' }, + { url: '/best-practices', title: 'Best Practices', group: 'Pages' }, + { url: '/guides', title: 'Guides', group: 'Pages' }, + { url: '/videos', title: 'Videos', group: 'Pages' }, ]; export function CommandMenu() { const [isActive, setIsActive] = useState(true); - const [pages, setPages] = useState(defaultPages); + const [allPages, setAllPages] = useState([]); + const [searchResults, setSearchResults] = useState(defaultPages); const [searchedText, setSearchedText] = useState(''); const [activeCounter, setActiveCounter] = useState(0); + async function getAllPages() { + if (allPages.length > 0) { + return allPages; + } + + const { error, response } = await httpGet(`/pages.json`); + if (!response) { + return defaultPages; + } + + setAllPages([...defaultPages, ...response]); + + return response; + } + + useEffect(() => { + if (!searchedText) { + setSearchResults(defaultPages); + return; + } + + const normalizedSearchText = searchedText.trim().toLowerCase(); + getAllPages().then((unfilteredPages = defaultPages) => { + const filteredPages = unfilteredPages.filter((currPage: PageType) => { + return ( + currPage.title.toLowerCase().indexOf(normalizedSearchText) !== -1 + ); + }); + + setActiveCounter(0); + setSearchResults(filteredPages); + }); + }, [searchedText]); + if (!isActive) { return null; } @@ -23,38 +66,45 @@ export function CommandMenu() {
{ const value = (e.target as HTMLInputElement).value.trim(); setSearchedText(value); }} onKeyDown={(e) => { if (e.key === 'ArrowDown') { - const canGoNext = activeCounter < pages.length - 1; + const canGoNext = activeCounter < searchResults.length - 1; setActiveCounter(canGoNext ? activeCounter + 1 : 0); } else if (e.key === 'ArrowUp') { const canGoPrev = activeCounter > 0; setActiveCounter( - canGoPrev ? activeCounter - 1 : pages.length - 1 + canGoPrev ? activeCounter - 1 : searchResults.length - 1 ); + } else if (e.key === 'Tab') { + e.preventDefault(); } else if (e.key === 'Enter') { - // const activePage = pages[activeCounter] + const activePage = searchResults[activeCounter]; + if (activePage) { + window.location.href = activePage.url; + } } }} /> -
+
- {pages.map((page, counter) => ( + {searchResults.map((page, counter) => ( setActiveCounter(counter)} - href={page.href} + href={page.url} > {searchedText && ( {page.group} diff --git a/src/pages/pages.json.astro b/src/pages/pages.json.astro deleted file mode 100644 index d467d09b8..000000000 --- a/src/pages/pages.json.astro +++ /dev/null @@ -1,36 +0,0 @@ ---- -import { getAllBestPractices } from '../lib/best-pratice'; -import { getAllGuides } from '../lib/guide'; -import { getRoadmapsByTag } from '../lib/roadmap'; -import { getAllVideos } from '../lib/video'; - -const guides = await getAllGuides(); -const videos = await getAllVideos(); -const roadmaps = await getRoadmapsByTag('roadmap'); -const bestPractices = await getAllBestPractices(); - -const formattedData = [ - ...roadmaps.map((roadmap) => ({ - url: `/${roadmap.id}`, - title: roadmap.frontmatter.briefTitle, - group: 'Roadmaps', - })), - ...bestPractices.map((bestPractice) => ({ - url: `/${bestPractice.id}`, - title: bestPractice.frontmatter.briefTitle, - group: 'Best Practices', - })), - ...guides.map((guide) => ({ - url: `/${guide.id}`, - title: guide.frontmatter.title, - group: 'Guides', - })), - ...videos.map((guide) => ({ - url: `/${guide.id}`, - title: guide.frontmatter.title, - group: 'Videos', - })), -]; ---- - -{JSON.stringify(formattedData)} diff --git a/src/pages/pages.json.ts b/src/pages/pages.json.ts new file mode 100644 index 000000000..523d1f8e1 --- /dev/null +++ b/src/pages/pages.json.ts @@ -0,0 +1,36 @@ +import { getAllBestPractices } from '../lib/best-pratice'; +import { getAllGuides } from '../lib/guide'; +import { getRoadmapsByTag } from '../lib/roadmap'; +import { getAllVideos } from '../lib/video'; + +export async function get() { + const guides = await getAllGuides(); + const videos = await getAllVideos(); + const roadmaps = await getRoadmapsByTag('roadmap'); + const bestPractices = await getAllBestPractices(); + + return { + body: JSON.stringify([ + ...roadmaps.map((roadmap) => ({ + url: `/${roadmap.id}`, + title: roadmap.frontmatter.briefTitle, + group: 'Roadmaps', + })), + ...bestPractices.map((bestPractice) => ({ + url: `/best-practices/${bestPractice.id}`, + title: bestPractice.frontmatter.briefTitle, + group: 'Best Practices', + })), + ...guides.map((guide) => ({ + url: `/${guide.id}`, + title: guide.frontmatter.title, + group: 'Guides', + })), + ...videos.map((guide) => ({ + url: `/${guide.id}`, + title: guide.frontmatter.title, + group: 'Videos', + })), + ]), + }; +}