feat: add site search with pagefind

This commit is contained in:
Stefan Imhoff
2023-06-29 17:03:18 +02:00
parent 133c976389
commit 4519a27258
17 changed files with 319 additions and 323 deletions

View File

@@ -2,10 +2,11 @@
import { Link } from '.';
import navigation from '../data/navigation.json';
import SearchLink from './SearchLink.astro';
---
<nav
class="navigation col-span-12 col-start-4 self-center md:col-span-14 md:col-start-3"
class="navigation col-span-12 col-start-4 flex items-center self-center md:col-span-14 md:col-start-3"
role="navigation"
aria-label="Main"
>
@@ -23,4 +24,5 @@ import navigation from '../data/navigation.json';
))
}
</ul>
<SearchLink />
</nav>

View File

@@ -15,6 +15,7 @@ import '../styles/sal.css';
declare const sal: any;
const swup = new Swup({
ignoreVisit: (url, { el } = {}) => el?.closest('[data-pagefind-ui] a'),
plugins: [
new SwupFadeTheme(),
new SwupHeadPlugin(),
@@ -41,6 +42,7 @@ import '../styles/sal.css';
}
}
// Register scripts after swup page transition
swup.on('pageView', () => {
if (typeof sal !== 'undefined') {
sal({
@@ -50,6 +52,8 @@ import '../styles/sal.css';
setActiveLink();
setUpLink();
setEmailLink();
setSearchModalLink();
setSearchLink();
}
});
@@ -78,6 +82,45 @@ import '../styles/sal.css';
});
}
function setSearchLink() {
const dialog = document.querySelector('dialog');
const openDialogLink = document.getElementById('search-link');
openDialogLink?.addEventListener('click', (event) => {
event.preventDefault();
dialog?.showModal();
});
document.addEventListener('keydown', (event) => {
if (event.key === '/') {
event.preventDefault();
dialog?.showModal();
}
});
}
function setSearchModalLink() {
const dialog = document.querySelector('dialog');
dialog?.addEventListener('click', (event) => {
if (event.target === dialog) {
if (!dialog.classList.contains('hide')) {
dialog.classList.add('hide');
dialog.addEventListener(
'animationend',
(animationEvent) => {
if (animationEvent.animationName === 'hide-modal') {
dialog.close();
dialog.classList.remove('hide');
}
},
{ once: true }
);
}
}
});
}
function handleEmailClick(event: Event) {
event.preventDefault();
const currentTarget = event.currentTarget;
@@ -101,6 +144,8 @@ import '../styles/sal.css';
setActiveLink();
setUpLink();
setEmailLink();
setSearchLink();
setSearchModalLink();
</script>
<style is:global>

View File

@@ -0,0 +1,20 @@
---
import { Sprite } from 'astro-icon';
import { Link } from '.';
---
<Link
class="col-span-2 col-start-1 h-clickarea w-clickarea items-center justify-center self-center justify-self-center transition-transform duration-500 ease-in-out hover:scale-75 focus:scale-75 print:hidden md:col-span-1"
id="search-link"
title="Search (/)"
>
<button
aria-label="Search the website (/)"
class="flex h-clickarea w-clickarea cursor-pointer items-center justify-center border-none text-[0]"
tabindex={-1}
type="button"
>
<Sprite name="ri:search-line" class="h-icon w-icon" />
</button>
</Link>

View File

@@ -0,0 +1,118 @@
---
import Search from 'astro-pagefind/components/Search';
---
<dialog>
<Search />
</dialog>
<style is:global>
dialog::backdrop {
@apply bg-black/50 backdrop-blur-sm;
animation: show-dimmer 0.5s ease-in-out;
}
dialog.hide::backdrop {
animation: hide-dimmer 0.5s ease-in-out;
}
dialog[open] {
@apply h-[80vh] w-[80vw] max-w-[40em] bg-shibui-100 font-sans font-normal leading-relaxed text-shibui-950 common-ligatures dark:border-1 dark:border-solid dark:border-shibui-200/[0.25] dark:bg-shibui-900 dark:text-shibui-200/[0.87];
animation: show-modal 0.5s ease-in-out;
}
dialog.hide {
animation: hide-modal 0.5s ease-in-out;
}
@keyframes show-modal {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes show-dimmer {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes hide-modal {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(50px);
}
}
@keyframes hide-dimmer {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.pagefind-ui {
@apply bg-shibui-100 !font-sans !font-normal !leading-relaxed text-shibui-950 common-ligatures dark:bg-shibui-900 dark:text-shibui-200/[0.87];
}
.pagefind-ui__form::before {
@apply !hidden;
}
.pagefind-ui__search-input,
.pagefind-ui__search-clear {
@apply !bg-shibui-100 !text-shibui-950 dark:!bg-shibui-850 dark:!text-shibui-200/[0.87];
}
.pagefind-ui__search-input {
@apply !border-1 !border-solid !border-shibui-900/[0.25] !bg-shibui-100 !text-shibui-950 !pis-7 dark:!border-shibui-200/[0.25] dark:!bg-shibui-850 dark:!text-shibui-200/[0.87];
}
.pagefind-ui__search-clear {
@apply !inline-end-4;
}
.pagefind-ui__result {
@apply !border-solid !border-black/[0.1] !border-be-1 !border-bs-0 !border-ie-0 !border-is-0 dark:!border-white/[0.1];
}
.pagefind-ui__result-inner,
.pagefind-ui__message,
.pagefind-ui__result-link {
@apply !text-shibui-950 dark:!text-shibui-200/[0.87];
}
.pagefind-ui__result-link {
@apply inline !font-semibold !text-shibui-950 underline !decoration-shibui-900/20 !decoration-4 underline-offset-auto no-common-ligatures hover:!decoration-accent focus:!decoration-accent dark:!text-shibui-100;
}
.pagefind-ui .pagefind-ui__result-link {
@apply !text-3 !font-black leading-tight;
}
.pagefind-ui .pagefind-ui__result-excerpt {
@apply !text-2;
}
.pagefind-ui__result-excerpt mark {
@apply !rounded !border !border-black/[0.1] !bg-marked !text-black/[0.75] !pli-[0.3em] !pbe-[0.2em] !pbs-[0.3em] dark:!bg-marked/[0.7];
}
.pagefind-ui__button {
@apply !border-1 !border-solid !border-shibui-900/[0.25] !bg-shibui-200 !text-shibui-950 hover:!bg-shibui-300 dark:!border-shibui-200/[0.25] dark:!bg-shibui-950 dark:!text-shibui-200/[0.87] dark:hover:!bg-shibui-800;
}
</style>

View File

@@ -8,6 +8,7 @@ import { isProduction } from '../utils';
import ThemeProvider from '../components/ThemeProvider.astro';
import PageHeader from '../components/PageHeader.astro';
import PageFooter from '../components/PageFooter.astro';
import SearchModal from '../components/SearchModal.astro';
import Scripts from '../components/Scripts.astro';
export interface Props {
@@ -44,6 +45,7 @@ const schema = JSON.stringify({
url: site.url,
});
const pagefind = !noindex && { 'data-pagefind-body': '' };
const webManifest = isProduction && {
rel: 'manifest',
href: '/manifest.webmanifest',
@@ -164,13 +166,14 @@ const webManifest = isProduction && {
<Sprite.Provider>
{header && <PageHeader backLink={backLink} />}
<div class="page-content flex grow">
<main class="h-full w-full">
<main class="h-full w-full" {...pagefind}>
<slot />
</main>
</div>
{footer && <PageFooter />}
</Sprite.Provider>
</div>
<SearchModal />
<script>
console.info(
'👋 I see youre interested in the source code of this site? You can find it here 👉 https://github.com/kogakure/website-astro-stefanimhoff.de'

View File

@@ -33,6 +33,7 @@ const description = 'This is a collection of AI art pieces Ive created with S
</article>
<nav class="col-start-1 col-end-18 md:col-start-1 md:col-end-16" aria-label="AI Art">
data-pagefind-ignore
<ol
class="gap-[max(25px,_2vw)] md:grid md:grid-flow-row-dense md:auto-rows-[50px] md:grid-cols-[repeat(auto-fit,_minmax(50px,_1fr))] md:grid-rows-[50px]"
>

View File

@@ -39,6 +39,7 @@ The source code of this website is available on [GitHub](https://github.com/koga
- The scroll animations are created with [Sal](https://mciastek.github.io/sal/) and for page transitions I use [Swup](https://swup.js.org/).
- Icons are handled by [Astro Icon](https://github.com/natemoo-re/astro-icon).
- All images are optimized with [Astro ImageTools](https://github.com/RafidMuhymin/astro-imagetools/).
- My site search is build with [Pagefind](https://pagefind.app/) using the [Astro-Pagefind](https://github.com/shishkin/astro-pagefind) integration.
- I use YouTube Lite, provided by [Astro Embed](https://github.com/astro-community/astro-embed).
- [Astro SEO](https://github.com/jonasmerlin/astro-seo) makes it easy to add the SEO relevant information.
- I use [Astro Webmanifest](https://github.com/alextim/astro-lib/tree/main/packages/astro-webmanifest) and [Astro Service Worker](https://github.com/tatethurston/astrojs-service-worker) to optimize the website.

View File

@@ -30,8 +30,9 @@ const description =
</article>
<nav
class="col-start-1 col-end-17 print:hidden md:col-start-2 md:col-end-14"
aria-label="Haiku"
class="col-start-1 col-end-17 print:hidden md:col-start-2 md:col-end-14"
data-pagefind-ignore
>
<ol
class="grid list-none grid-cols-[repeat(auto-fill,_minmax(3rem,_1fr))] justify-items-center gap-[1rem]"

View File

@@ -87,6 +87,7 @@ rssPosts.sort(sortMarkdownByDate);
<article
class="min-[1794px]:[&_li:block col-start-2 col-end-18 grid w-full grid-cols-18 gap-y-gap mbe-12 min-[1097px]:[&_li:nth-child(n+5)]:hidden min-[1410px]:[&_li:nth-child(n+5)]:block min-[1411px]:[&_li:nth-child(n+6)]:hidden min-[1793px]:[&_li:nth-child(n+6)]:block"
data-pagefind-ignore
{...animation}
>
<JournalList entries={formattedLatest} />

View File

@@ -29,6 +29,7 @@ const description = 'I am writing essays about various topics in this Journal.';
<article
class="col-start-1 col-end-18 grid md:col-start-4 md:col-end-12 xl:col-start-5 xl:col-end-11"
data-pagefind-ignore
{...animation}
>
<Intro components={mapping} />

View File

@@ -32,8 +32,9 @@ const description = 'This is a collection of Sketchnotes Ive drawn.';
</article>
<nav
class="col-start-1 col-end-18 w-full md:col-start-1 md:col-end-16"
aria-label="Sketchnotes"
class="col-start-1 col-end-18 w-full md:col-start-1 md:col-end-16"
data-pagefind-ignore
>
<ol
class="gap-[max(25px,_2vw)] print:block md:grid md:grid-flow-row-dense md:auto-rows-[50px] md:grid-cols-[repeat(auto-fit,_minmax(50px,_1fr))] md:grid-rows-[50px]"