Skip to content

Commit

Permalink
feat: add search
Browse files Browse the repository at this point in the history
  • Loading branch information
Barbapapazes committed Jul 6, 2023
1 parent 9efb4e1 commit 7525146
Show file tree
Hide file tree
Showing 25 changed files with 293 additions and 0 deletions.
Empty file modified docs/.env.example
100755 → 100644
Empty file.
Empty file modified docs/.gitignore
100755 → 100644
Empty file.
Empty file modified docs/content/1.index.md
100755 → 100644
Empty file.
Empty file modified docs/content/3.guide/1.writing/2.markdown.md
100755 → 100644
Empty file.
Empty file modified docs/content/3.guide/1.writing/3.mdc.md
100755 → 100644
Empty file.
Empty file modified docs/content/4.api/1.components/7.prose.md
100755 → 100644
Empty file.
Empty file modified docs/nuxt.config.ts
100755 → 100644
Empty file.
Empty file modified docs/package.json
100755 → 100644
Empty file.
Empty file modified docs/renovate.json
100755 → 100644
Empty file.
Empty file modified docs/tsconfig.json
100755 → 100644
Empty file.
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
"@nuxtjs/eslint-config-typescript": "latest",
"@types/mdurl": "^1.0.2",
"@types/ws": "^8.5.5",
"@vueuse/core": "^10.2.1",
"@vueuse/integrations": "^10.2.1",
"@vueuse/nuxt": "^10.2.1",
"c8": "^8.0.0",
"csvtojson": "^2.0.10",
"eslint": "^8.43.0",
Expand All @@ -102,6 +105,9 @@
"vitest": "^0.32.2",
"vue-docgen-web-types": "^0.1.8"
},
"peerDependencies": {
"fuse.js": "^6.6.2"
},
"packageManager": "pnpm@8.6.5",
"pnpm": {
"peerDependencyRules": {
Expand Down
9 changes: 9 additions & 0 deletions playground/search/content/javascript.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
description: JavaScript, a programming language!
---

# JavaScript

JavaScript (/ˈdʒɑːvəskrɪpt/), often abbreviated as JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS. As of 2023, 98.7% of websites use JavaScript on the client side for webpage behavior, often incorporating third-party libraries. All major web browsers have a dedicated JavaScript engine to execute the code on users' devices.

For more information, see [Wikipedia](https://en.wikipedia.org/wiki/JavaScript).
9 changes: 9 additions & 0 deletions playground/search/content/php.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
description: PHP, a programming language!
---

# PHP

PHP is a general-purpose scripting language geared towards web development. It was originally created by Danish-Canadian programmer Rasmus Lerdorf in 1993 and released in 1995. The PHP reference implementation is now produced by the PHP Group. PHP was originally an abbreviation of Personal Home Page, but it now stands for the recursive initialism PHP: Hypertext Preprocessor.

For more information, see [Wikipedia](https://en.wikipedia.org/wiki/PHP).
13 changes: 13 additions & 0 deletions playground/search/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default defineNuxtConfig({
extends: ['../shared'],

content: {
search: {
mode: 'full-text'
}
},

typescript: {
includeWorkspace: true
}
})
15 changes: 15 additions & 0 deletions playground/search/pages/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts" setup>
const search = ref('')
const result = await useSearch(search)
</script>

<template>
<div>
<h1>Search</h1>
<p>Search page</p>

<input v-model="search">

<pre>{{ result }} </pre>
</div>
</template>
128 changes: 128 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file modified scripts/bump-edge.ts
100755 → 100644
Empty file.
Empty file modified scripts/example.sh
100755 → 100644
Empty file.
Empty file modified scripts/fixture.sh
100755 → 100644
Empty file.
Empty file modified scripts/playground.sh
100755 → 100644
Empty file.
Empty file modified scripts/release-edge.sh
100755 → 100644
Empty file.
Empty file modified scripts/test.sh
100755 → 100644
Empty file.
35 changes: 35 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,17 @@ export interface ModuleOptions {
navigation: false | {
fields: Array<string>
}
/**
* Search mode.
*
* @default false
*/
search: false | {
/**
* Used to determine how to search content.
*/
mode: 'full-text' | 'meta'
}
/**
* List of locale codes.
* This codes will be used to detect contents locale.
Expand Down Expand Up @@ -280,6 +291,7 @@ export default defineNuxtModule<ModuleOptions>({
navigation: {
fields: []
},
search: false,
documentDriven: false,
experimental: {
clientDB: false,
Expand Down Expand Up @@ -347,6 +359,14 @@ export default defineNuxtModule<ModuleOptions>({
}
)

if (options.search) {
nitroConfig.handlers.push({
method: 'get',
route: `${options.api.baseURL}/search`,
handler: resolveRuntimeModule('./server/api/search')
})
}

if (!nuxt.options.dev) {
nitroConfig.prerender.routes.unshift(`${options.api.baseURL}/cache.${buildIntegrity}.json`)
}
Expand Down Expand Up @@ -410,6 +430,18 @@ export default defineNuxtModule<ModuleOptions>({
{ name: 'useUnwrap', as: 'useUnwrap', from: resolveRuntimeModule('./composables/utils') }
])

if (options.search) {
nuxt.options.modules.push('@vueuse/nuxt')

addImports([
{
name: 'useSearch',
as: 'useSearch',
from: resolveRuntimeModule('./composables/search')
}
])
}

// Register components
await addComponentsDir({
path: resolve('./runtime/components'),
Expand Down Expand Up @@ -617,6 +649,7 @@ export default defineNuxtModule<ModuleOptions>({
documentDriven: options.documentDriven as any,
host: typeof options.documentDriven !== 'boolean' ? options.documentDriven?.host ?? '' : '',
trailingSlash: typeof options.documentDriven !== 'boolean' ? options.documentDriven?.trailingSlash ?? false : false,
search: options.search,
// Anchor link generation config
anchorLinks: options.markdown.anchorLinks as { depth?: number, exclude?: number[] }
})
Expand Down Expand Up @@ -746,6 +779,8 @@ interface ModulePublicRuntimeConfig {

navigation: ModuleOptions['navigation']

search: ModuleOptions['search']

documentDriven: ModuleOptions['documentDriven']
}

Expand Down
31 changes: 31 additions & 0 deletions src/runtime/composables/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useFuse } from '@vueuse/integrations/useFuse'
import { useRuntimeConfig, useLazyFetch } from '#imports'

export const useSearch = async (query: string) => {
const baseAPI = useRuntimeConfig().public.content.api.baseURL

// TODO: find a way to avoid fetching every time all the content
const { data } = await useLazyFetch(`${baseAPI}/search`)

// TODO: add a way to configure the search (using options from search?)
const { results } = useFuse(query,
data,
{
fuseOptions: {
keys: [
'title',
'description',
'keywords',
'body'
],
ignoreLocation: true,
threshold: 0,
includeMatches: true,
includeScore: true
},
matchAllWhenSearchEmpty: true
}
)

return results
}
47 changes: 47 additions & 0 deletions src/runtime/server/api/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { defineEventHandler } from 'h3'
import { serverQueryContent } from '../storage'
import { useRuntimeConfig } from '#imports'

export default defineEventHandler(async (event) => {
const { search } = useRuntimeConfig().public.content
const isFullTextMode = search?.mode === 'full-text'

const files = await serverQueryContent(event).find()

const docs = await Promise.all(
files
.filter((file) => {
return file?._extension === 'md' &&
file?._draft === false && file?._empty === false
})
.map(
async ({ _id: id, _path: path, _dir: dir, title = '', description = '', body = undefined, ...rest }) => {

Check failure on line 18 in src/runtime/server/api/search.ts

View workflow job for this annotation

GitHub Actions / ci

'rest' is defined but never used. Allowed unused args must match /^_/u

Check failure on line 18 in src/runtime/server/api/search.ts

View workflow job for this annotation

GitHub Actions / ci

Async arrow function has no 'await' expression
// TODO: add configuration to choose which fields to index
return {
id,
path,
dir,
title,
description,
keywords: body?.toc?.links.map(link => link?.text),
body: isFullTextMode ? extractTextFromAst(body) : ''
}
}
)
)

return docs
})

function extractTextFromAst (node) {
let text = ''
if (node.type === 'text') {
text += node.value
}
if (node.children) {
for (const child of node.children) {
text += ' ' + extractTextFromAst(child)
}
}
return text
}

0 comments on commit 7525146

Please sign in to comment.