Last active
November 5, 2021 14:05
-
-
Save vojtaholik/36795499ad007e324660352d02217cd8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Menu: Search egghead.io | |
// Description: Browse egghead.io's lesson library | |
// Shortcut: cmd option e | |
// Author: egghead.io | |
// Twitter: @eggheadio | |
/** @type {import("@johnlindquist/kit")} */ | |
let algoliasearch = await npm("algoliasearch"); | |
let app = await env("EGGHEAD_PUBLIC_ALGOLIA_APP"); | |
let key = await env("EGGHEAD_PUBLIC_ALGOLIA_KEY"); | |
let client = algoliasearch(app, key); | |
let index = client.initIndex("content_production"); | |
let hit = await arg( | |
{ | |
placeholder: "Search egghead:", | |
ignoreBlur: true, | |
input: "react", | |
}, | |
async (input) => { | |
if (input) { | |
let { hits } = await index.search(input); | |
return hits.map((hit) => { | |
return { | |
name: hit.title, | |
value: hit, | |
// tag: '', // TODO: tag could be number of lessons, but it's not available here | |
img: hit.image, | |
description: hit.instructor_name, | |
preview: async () => { | |
// We _could_ query the egghead api here, but I think we have enough info already? π€ | |
// TODO: Delay fetching individual lessons to avoid lagginess? | |
let lessons = await fetch( | |
`https://app.egghead.io/api/v1/playlists/${hit.slug}/items?flatten=true` | |
).then((r) => r.json()); | |
// This doesn't seem to be working properly. | |
if (lessons) { | |
setFlags({ | |
instructor: { | |
name: "View instructor profile", | |
description: "Open the instructor profile in your browser", | |
shortcut: "cmd+i", | |
url: `https://egghead.io/${hit.instructor_path}`, | |
}, | |
twitter: { | |
name: "View instructor's twitter", | |
description: "Open the instructor twitter account", | |
shortcut: "cmd+t", | |
url: `https://twitter.com/${hit.instructor.twitter}`, | |
}, | |
website: { | |
name: "View instructor's website", | |
description: "Open the instructor website", | |
shortcut: "cmd+w", | |
}, | |
...lessons.map((lesson, i) => ({ | |
name: `${i + 1}: ${lesson.title}`, | |
description: convertTimeWithTitles(lesson.duration), | |
shortcut: `cmd+${i + 1}`, | |
url: `https://egghead.io${lesson.path}`, | |
})), | |
}); | |
} | |
return ` | |
<div class="border-l dark:border-white dark:border-opacity-5 border-black border-opacity-5 h-full min-h-screen"> | |
<div class="grid grid-cols-3 border-b dark:border-white dark:border-opacity-5 border-black border-opacity-5"> | |
<div class="col-span-2 border-r dark:border-white dark:border-opacity-5 border-black border-opacity-5 flex flex-col"> | |
<h1 class="p-5 h-full text-xl leading-tight font-semibold m-0">${ | |
hit.title | |
}</h1> | |
<div class="pl-5 pr-2 py-2 flex items-center space-x-3 text-xs border-t dark:border-white dark:border-opacity-5 border-black border-opacity-5"> | |
<div class="flex items-center"> | |
<div class="rounded-full overflow-hidden w-8 h-8 flex items-center justify-center"> | |
<img src="${hit.instructor_avatar_url}" /> | |
</div> | |
<span class="pl-2">${hit.instructor_name}</span> | |
</div> | |
<div class="${ | |
hit.access_state === "pro" | |
? "bg-yellow-500 text-white border border-transparent" | |
: "text-yellow-500 border border-yellow-500" | |
} rounded-full leading-none px-2 py-1 text-xs uppercase"> | |
${hit.access_state} | |
</div> | |
<div> | |
${convertTimeWithTitles(hit.duration)} | |
</div> | |
</div> | |
</div> | |
<div class="p-5"> | |
<img src="${hit.image}" /> | |
</div> | |
</div> | |
<div class="p-5 border-b dark:border-white dark:border-opacity-5 border-black border-opacity-5"> | |
<article class="prose prose-sm dark:prose-dark"> | |
${md(hit.description)} | |
</article> | |
</div> | |
<ul class="text-sm list-none list-inside m-0"> | |
<div class="uppercase text-xs pb-2 tracking-wide opacity-60 px-5 pt-5">Lessons</div> | |
${lessons | |
?.map((lesson, i) => { | |
return ` | |
<li class="list-none"> | |
<a class="dark:hover:bg-white dark:hover:bg-opacity-5 flex items-baseline py-3 px-5 border-b dark:border-white dark:border-opacity-5 border-black border-opacity-5 font-medium" | |
href="https://egghead.io${lesson.path}"> | |
<span class="opacity-50 pr-2 text-xs">${i + 1}</span> | |
${lesson.title} | |
</a> | |
</li> | |
`; | |
}) | |
.join("")} | |
</ul> | |
</div> | |
`; | |
}, | |
}; | |
}); | |
} | |
} | |
); | |
let url = hit.url; | |
if (flag?.instructor) url = `https://egghead.io/${hit.instructor_path}`; | |
if (flag?.twitter) url = `https://twitter.com/${hit.instructor.twitter}`; | |
if (flag?.website) url = `${hit.instructor.twitter}`; | |
// TODO: Make this work for lessons inside flags menu | |
await $`open ${url}`; | |
// ββββ UTILS ββββ | |
function convertTimeWithTitles(seconds) { | |
if (seconds < 0) seconds = 0; | |
const hours = ~~(seconds / 3600); | |
const mins = ~~((seconds - hours * 3600) / 60); | |
const secs = (seconds - hours * 3600 - mins * 60) % 60; | |
let result = ""; | |
if (hours) result += hours + "h "; | |
if (mins) result += mins + "m "; | |
if (mins < 1) result += secs + "s "; | |
return result.trim(); | |
} | |
// TODO: | |
// - Lazy load more results (results from algolia are paginated) | |
// - Sometimes using space in search term errors out. No results fail - something to do with fetching lessons? | |
// - Fix flags for lessons, they don't work properly | |
// - Flags URL not working | |
// - Still issues with tailwind classes not being available | |
// - Script "frontmatter" parser takes all instances of `// shortcut: "cmd+w"` from the file, so one must remember to be careful |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment