Skip to content

Commit

Permalink
Merge pull request #115 from vinhphm/refined-search
Browse files Browse the repository at this point in the history
New and improved search UI
  • Loading branch information
vinhphm authored Dec 8, 2024
2 parents c002097 + 8cecb84 commit 834bbb5
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 148 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ node_modules
.eslintcache
.env
*.log

public/pagefind/
15 changes: 14 additions & 1 deletion astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeExternalLinks from 'rehype-external-links'
import rehypePrettyCode from 'rehype-pretty-code'
import UnoCSS from 'unocss/astro'
import pagefind from 'vite-plugin-pagefind'
import siteConfig from './src/site-config'

export default defineConfig({
site: 'https://vinh.dev',
site: siteConfig.site,
trailingSlash: 'never',
build: {
assets: '_assets',
Expand All @@ -23,6 +25,17 @@ export default defineConfig({
experimental: {
svg: true,
},
vite: {
ssr: {
noExternal: [`${siteConfig.site}/pagefind/pagefind.js`],
},
plugins: [pagefind()],
build: {
rollupOptions: {
external: [`${siteConfig.site}/pagefind/pagefind.js`],
},
},
},
integrations: [
mdx(),
sitemap(),
Expand Down
Binary file modified bun.lockb
Binary file not shown.
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
"prepare": "simple-git-hooks",
"compress": "esno scripts/img-compress-staged.ts",
"dev": "astro dev --host",
"build": "astro build",
"postbuild": "pagefind --site dist",
"build": "astro build && pagefind",
"preview": "astro preview",
"lint": "eslint .",
"lint:fix": "eslint --fix",
Expand All @@ -18,6 +17,7 @@
"@astrojs/mdx": "^4.0.1",
"@astrojs/rss": "4.0.9",
"@astrojs/sitemap": "3.2.1",
"@astrojs/svelte": "^7.0.1",
"@astrojs/vue": "^5.0.1",
"@unocss/reset": "^0.65.1",
"astro": "^5.0.2",
Expand Down Expand Up @@ -57,7 +57,8 @@
"reading-time": "^1.5.0",
"rehype-pretty-code": "^0.14.0",
"simple-git": "^3.27.0",
"simple-git-hooks": "^2.11.1"
"simple-git-hooks": "^2.11.1",
"vite-plugin-pagefind": "^0.2.10"
},
"simple-git-hooks": {
"pre-commit": "bunx esno scripts/reading-time-hook.ts && bunx lint-staged"
Expand Down
4 changes: 4 additions & 0 deletions pagefind.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"site": "dist",
"vite_plugin_pagefind": {}
}
4 changes: 3 additions & 1 deletion src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getLinkTarget } from '@/utils/link'
import siteConfig from '@/site-config'
import GlitchingLogo from './GlitchingLogo.vue'
import Search from './Search.vue'
import CommandPalette from './SearchCommandPalette.vue'
import ThemeToggle from './ThemeToggle.vue'
const navLinks = siteConfig.header.navLinks || []
Expand Down Expand Up @@ -48,11 +49,12 @@ const socialLinks = structuredClone(siteConfig.socialLinks).filter((link: Record
/>
))}
<a target="_blank" href="/rss.xml" class="lt-md:hidden i-ri-rss-line nav-link" aria-label="RSS" />
<Search client:load />
<Search client:visible />
<ThemeToggle client:load />
</div>
</nav>
</header>
<CommandPalette client:load />

<style>
.header h1 {
Expand Down
147 changes: 6 additions & 141 deletions src/components/Search.vue
Original file line number Diff line number Diff line change
@@ -1,145 +1,10 @@
<script lang="ts" setup>
import { animate } from 'motion'
import { onMounted, onUnmounted, ref } from 'vue'
import '@pagefind/default-ui/css/ui.css'
const dialog = ref<HTMLDialogElement | null>(null)
const dialogFrame = ref<HTMLElement | null>(null)
const isDev = ref(import.meta.env.DEV)
function openModal(event?: MouseEvent) {
if (dialog.value) {
dialog.value.showModal()
animate(
dialog.value,
{
clipPath: [
'polygon(0 0, 100% 0, 100% -200%, -200% -200%)',
'polygon(0 0, 100% 0, 100% 100%, 0% 100%)',
],
opacity: [0, 1],
},
{ duration: 0.2 },
)
document.body.classList.add('overflow-hidden')
dialog.value.querySelector('input')?.focus()
event?.stopPropagation()
window.addEventListener('click', onWindowClick)
window.addEventListener('keydown', handleEscKey)
}
}
function closeModal() {
if (dialog.value) {
dialog.value.close()
document.body.classList.remove('overflow-hidden')
window.removeEventListener('click', onWindowClick)
window.removeEventListener('keydown', handleEscKey)
}
}
function onWindowClick(event: MouseEvent) {
if (
document.body.contains(event.target as Node) &&
!dialogFrame.value?.contains(event.target as Node)
) {
closeModal()
}
}
function handleEscKey(e: KeyboardEvent) {
if (e.key === 'Escape' && dialog.value?.open) {
closeModal()
}
}
onMounted(() => {
const openBtn = document.querySelector<HTMLButtonElement>('button[data-open-modal]')
const closeBtn = document.querySelector<HTMLButtonElement>('button[data-close-modal]')
if (openBtn) {
openBtn.addEventListener('click', openModal)
openBtn.disabled = false
}
if (closeBtn) {
closeBtn.addEventListener('click', closeModal)
}
window.addEventListener('keydown', (e) => {
if (e.key === '/' && !dialog.value?.open) {
openModal()
e.preventDefault()
}
})
if (!isDev.value) {
const onIdle = window.requestIdleCallback || (cb => setTimeout(cb, 1))
onIdle(async () => {
// @ts-expect-error package does not export types
const { PagefindUI } = await import('@pagefind/default-ui')
const _pagefindUI = new PagefindUI({
element: '#pagefind__search',
baseUrl: import.meta.env.BASE_URL,
bundlePath: `${import.meta.env.BASE_URL.replace(/\/$/, '')}/pagefind/`,
showImages: false,
})
})
}
})
onUnmounted(() => {
window.removeEventListener('click', onWindowClick)
window.removeEventListener('keydown', handleEscKey)
})
<script setup lang="ts">
import { showSearch } from '@/stores/search'
</script>

<template>
<site-search id="search" class="ms-auto">
<button data-open-modal class="flex items-center justify-center gap-1 rounded-md">
<span class="i-ri-search-line" />
</button>
<dialog
ref="dialog"
aria-label="search"
class="mb-auto mt-16 max-h-[calc(100%-8rem)] max-w-full min-h-[15rem] w-full border border-zinc-500/25 bg-[#ffffffec] opacity-0 shadow sm:mx-auto sm:max-w-[48rem] sm:w-5/6 sm:rounded-md dark:bg-[#0a0910ec] backdrop:backdrop-blur"
>
<div ref="dialogFrame" class="dialog-frame flex flex-col gap-4 p-6 pt-0">
<!-- <button
data-close-modal
class="ms-auto cursor-pointer rounded-full bg-zinc-200 px-4 py-2 dark:bg-zinc-700"
>
Close
</button> -->
<span class="sticky top-0 z-10 flex items-center justify-center gap-1 from-[#ffffffff] via-[#ffffffec] to-transparent from-60% to-100% via-80% bg-gradient-to-b py-4 text-xs text-zinc-500 -mx-6 dark:from-[#0a0910ff] dark:via-[#0a0910ec] dark:to-transparent dark:from-60% dark:to-100% dark:via-80% dark:bg-gradient-to-b dark:text-zinc-400">
Press
<kbd>esc</kbd>
or click outside to dismiss
</span>
<div v-if="isDev" class="mx-auto text-center dark:text-white">
<p>
Search is only available in production builds. <br>
Try building and previewing the site to test it out locally.
</p>
</div>
<div v-else class="search-container overflow-auto dark:text-white">
<div id="pagefind__search" class="overflow-auto" />
</div>
</div>
</dialog>
</site-search>
<button @click="showSearch = true">
<span class="sr-only">search</span>
<span class="i-ri-search-line" />
</button>
</template>

<style>
.dark {
--pagefind-ui-primary: #eeeeee;
--pagefind-ui-text: #eeeeee;
--pagefind-ui-background: #151616;
--pagefind-ui-border: #151616;
--pagefind-ui-tag: #151616;
}
.pagefind-ui__search-input:focus-visible {
outline: var(--pagefind-ui-border-width) solid var(--pagefind-ui-border);
}
</style>
Loading

0 comments on commit 834bbb5

Please sign in to comment.