mirror of
https://github.com/cupcakearmy/nicco.io.git
synced 2024-12-21 23:56:26 +00:00
add search
This commit is contained in:
parent
f1449a157c
commit
940cd5cea9
4
TODO.md
4
TODO.md
@ -1,3 +1,3 @@
|
|||||||
- Search
|
|
||||||
- Tag count
|
- Tag count
|
||||||
- Link in contact to status monitor
|
- title for pages
|
||||||
|
- check header meta info
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"@fontsource-variable/playfair-display": "^5.1.0",
|
"@fontsource-variable/playfair-display": "^5.1.0",
|
||||||
"@iconify-json/ion": "^1.2.1",
|
"@iconify-json/ion": "^1.2.1",
|
||||||
"astro": "^4.16.13",
|
"astro": "^4.16.13",
|
||||||
|
"fuse.js": "^7.0.0",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"rehype-autolink-headings": "^7.1.0",
|
"rehype-autolink-headings": "^7.1.0",
|
||||||
|
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@ -38,6 +38,9 @@ importers:
|
|||||||
astro:
|
astro:
|
||||||
specifier: ^4.16.13
|
specifier: ^4.16.13
|
||||||
version: 4.16.13(rollup@4.27.3)(sass@1.81.0)(stylus@0.64.0)(typescript@5.6.3)
|
version: 4.16.13(rollup@4.27.3)(sass@1.81.0)(stylus@0.64.0)(typescript@5.6.3)
|
||||||
|
fuse.js:
|
||||||
|
specifier: ^7.0.0
|
||||||
|
version: 7.0.0
|
||||||
mdast-util-to-string:
|
mdast-util-to-string:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0
|
version: 4.0.0
|
||||||
@ -1225,6 +1228,10 @@ packages:
|
|||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
|
fuse.js@7.0.0:
|
||||||
|
resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
gensync@1.0.0-beta.2:
|
gensync@1.0.0-beta.2:
|
||||||
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@ -3675,6 +3682,8 @@ snapshots:
|
|||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
fuse.js@7.0.0: {}
|
||||||
|
|
||||||
gensync@1.0.0-beta.2: {}
|
gensync@1.0.0-beta.2: {}
|
||||||
|
|
||||||
get-caller-file@2.0.5: {}
|
get-caller-file@2.0.5: {}
|
||||||
|
@ -5,6 +5,7 @@ export function remarkReadingTime() {
|
|||||||
return function (tree, { data }) {
|
return function (tree, { data }) {
|
||||||
const textOnPage = toString(tree)
|
const textOnPage = toString(tree)
|
||||||
const readingTime = getReadingTime(textOnPage)
|
const readingTime = getReadingTime(textOnPage)
|
||||||
|
data.astro.frontmatter.text = textOnPage
|
||||||
data.astro.frontmatter.readingTime = readingTime
|
data.astro.frontmatter.readingTime = readingTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,5 +45,9 @@ const description = 'Welcome to my website!'
|
|||||||
<meta property="twitter:description" content={description} />
|
<meta property="twitter:description" content={description} />
|
||||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||||
|
|
||||||
<script async defer src="https://spectare.nicco.io/unicorn.js" data-website-id="bc7525c5-6928-49e1-9255-aca296947def"
|
<script
|
||||||
></script>
|
is:inline
|
||||||
|
async
|
||||||
|
defer
|
||||||
|
src="https://spectare.nicco.io/unicorn.js"
|
||||||
|
data-website-id="bc7525c5-6928-49e1-9255-aca296947def"></script>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
import SearchIcon from '~icons/ion/search-outline'
|
||||||
const { pathname } = Astro.url
|
const { pathname } = Astro.url
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@ -14,11 +15,11 @@ const routes = [
|
|||||||
<h1 class:list={{ active: pathname === '/' }}>NB</h1>
|
<h1 class:list={{ active: pathname === '/' }}>NB</h1>
|
||||||
</a>
|
</a>
|
||||||
<ul>
|
<ul>
|
||||||
<!-- <li>
|
<li>
|
||||||
<a href="/search">
|
<a href="/search">
|
||||||
<Icon icon="search-outline" />
|
<SearchIcon />
|
||||||
</a>
|
</a>
|
||||||
</li> -->
|
</li>
|
||||||
{
|
{
|
||||||
routes.map(({ href, name }) => (
|
routes.map(({ href, name }) => (
|
||||||
<li>
|
<li>
|
||||||
|
66
src/components/PageSearch.svelte
Normal file
66
src/components/PageSearch.svelte
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
|
||||||
|
const { entries } = $props()
|
||||||
|
|
||||||
|
const fuse = new Fuse(entries, {
|
||||||
|
keys: ['text', 'url', 'extra'],
|
||||||
|
includeScore: true,
|
||||||
|
includeMatches: false,
|
||||||
|
minMatchCharLength: 2,
|
||||||
|
threshold: 0.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
let needle = $state('')
|
||||||
|
const results = $derived(fuse.search(needle))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input bind:value={needle} />
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
{#each results as result}
|
||||||
|
<li>
|
||||||
|
<a href={result.item.url}>
|
||||||
|
<span class="meta">
|
||||||
|
{result.item.type}
|
||||||
|
</span>
|
||||||
|
<span class="meta">
|
||||||
|
{(1 - result.score).toFixed(2)}
|
||||||
|
</span>
|
||||||
|
{result.item.title}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
input {
|
||||||
|
background: white;
|
||||||
|
border: 2px solid var(--clr-primary);
|
||||||
|
border-bottom-width: 4px;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--clr-secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta {
|
||||||
|
background: var(--clr-secondary);
|
||||||
|
width: fit-content;
|
||||||
|
padding: 0 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
39
src/pages/search.astro
Normal file
39
src/pages/search.astro
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
import { getCollection } from 'astro:content'
|
||||||
|
import PageSearch from '../components/PageSearch.svelte'
|
||||||
|
import PageWithTitle from '../layouts/PageWithTitle.astro'
|
||||||
|
|
||||||
|
type Entry = { url: string; type: 'post' | 'page'; title: string; text: string; extra?: any }
|
||||||
|
|
||||||
|
const entries: Entry[] = []
|
||||||
|
|
||||||
|
const posts = await getCollection('blog')
|
||||||
|
for (const post of posts) {
|
||||||
|
const rendered = await post.render()
|
||||||
|
const text = rendered.remarkPluginFrontmatter.text
|
||||||
|
entries.push({
|
||||||
|
url: `/blog/${post.slug}`,
|
||||||
|
type: 'post',
|
||||||
|
title: post.data.title,
|
||||||
|
text,
|
||||||
|
extra: post.data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const pages = await getCollection('page')
|
||||||
|
for (const page of pages) {
|
||||||
|
const rendered = await page.render()
|
||||||
|
const text = rendered.remarkPluginFrontmatter.text
|
||||||
|
entries.push({
|
||||||
|
url: `/${page.slug}`,
|
||||||
|
type: 'page',
|
||||||
|
title: page.data.title,
|
||||||
|
text,
|
||||||
|
extra: page.data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<PageWithTitle title="Search">
|
||||||
|
<PageSearch entries={entries} client:only="svelte" />
|
||||||
|
</PageWithTitle>
|
Loading…
Reference in New Issue
Block a user