Refactor pages and add retrieval

feat/cmd-k
Kamran Ahmed 2 years ago
parent 4d7cada25c
commit 44e5138b32
  1. 78
      src/components/CommandMenu/CommandMenu.tsx
  2. 36
      src/pages/pages.json.astro
  3. 36
      src/pages/pages.json.ts

@ -1,19 +1,62 @@
import { useState } from 'preact/hooks'; import { useEffect, useState } from 'preact/hooks';
import { httpGet } from '../../lib/http';
const defaultPages = [ type PageType = {
{ href: '/profile', title: 'Account', group: 'Pages' }, url: string;
{ href: '/roadmaps', title: 'Roadmaps', group: 'Pages' }, title: string;
{ href: '/best-practices', title: 'Best Practices', group: 'Pages' }, group: string;
{ href: '/guides', title: 'Guides', group: 'Pages' }, };
{ href: '/videos', title: 'Videos', group: 'Pages' },
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() { export function CommandMenu() {
const [isActive, setIsActive] = useState(true); const [isActive, setIsActive] = useState(true);
const [pages, setPages] = useState(defaultPages); const [allPages, setAllPages] = useState<PageType[]>([]);
const [searchResults, setSearchResults] = useState<PageType[]>(defaultPages);
const [searchedText, setSearchedText] = useState(''); const [searchedText, setSearchedText] = useState('');
const [activeCounter, setActiveCounter] = useState(0); const [activeCounter, setActiveCounter] = useState(0);
async function getAllPages() {
if (allPages.length > 0) {
return allPages;
}
const { error, response } = await httpGet<PageType[]>(`/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) { if (!isActive) {
return null; return null;
} }
@ -23,38 +66,45 @@ export function CommandMenu() {
<div className="relative top-20 h-full w-full max-w-lg p-2 md:h-auto"> <div className="relative top-20 h-full w-full max-w-lg p-2 md:h-auto">
<div className="relative rounded-lg bg-white shadow"> <div className="relative rounded-lg bg-white shadow">
<input <input
autofocus={true}
type="text" type="text"
value={searchedText} value={searchedText}
className="w-full rounded-t-md border-b p-4 text-sm focus:bg-gray-50 focus:outline-0" className="w-full rounded-t-md border-b p-4 text-sm focus:bg-gray-50 focus:outline-0"
placeholder="Search anywhere .." placeholder="Search anywhere .."
autocomplete="off"
onInput={(e) => { onInput={(e) => {
const value = (e.target as HTMLInputElement).value.trim(); const value = (e.target as HTMLInputElement).value.trim();
setSearchedText(value); setSearchedText(value);
}} }}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
const canGoNext = activeCounter < pages.length - 1; const canGoNext = activeCounter < searchResults.length - 1;
setActiveCounter(canGoNext ? activeCounter + 1 : 0); setActiveCounter(canGoNext ? activeCounter + 1 : 0);
} else if (e.key === 'ArrowUp') { } else if (e.key === 'ArrowUp') {
const canGoPrev = activeCounter > 0; const canGoPrev = activeCounter > 0;
setActiveCounter( 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') { } else if (e.key === 'Enter') {
// const activePage = pages[activeCounter] const activePage = searchResults[activeCounter];
if (activePage) {
window.location.href = activePage.url;
}
} }
}} }}
/> />
<div class="mt-2 px-2"> <div class="px-2 py-2">
<div className="flex flex-col"> <div className="flex flex-col">
{pages.map((page, counter) => ( {searchResults.map((page, counter) => (
<a <a
class={`block w-full rounded p-2 text-sm ${ class={`block w-full rounded p-2 text-sm ${
counter === activeCounter ? 'bg-gray-100' : '' counter === activeCounter ? 'bg-gray-100' : ''
}`} }`}
onMouseOver={() => setActiveCounter(counter)} onMouseOver={() => setActiveCounter(counter)}
href={page.href} href={page.url}
> >
{searchedText && ( {searchedText && (
<span class="mr-2 text-gray-400">{page.group}</span> <span class="mr-2 text-gray-400">{page.group}</span>

@ -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)}

@ -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',
})),
]),
};
}
Loading…
Cancel
Save