diff --git a/README.md b/README.md index 2b9c02d..3c3c9e3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ code-samples/ ├── typesense-astro-search/ # Astro + Typesense search implementation ├── typesense-gin-full-text-search/ # Go (Gin) + Typesense backend implementation ├── typesense-next-search-bar/ # Next.js + Typesense search implementation +├── typesense-nuxt-search-bar/ # Nuxt.js + Typesense search implementation ├── typesense-qwik-js-search/ # Qwik + Typesense search implementation ├── typesense-react-native-search-bar/ # React Native + Typesense search implementation ├── typesense-solid-js-search/ # SolidJS + Typesense search implementation @@ -25,6 +26,7 @@ code-samples/ | [typesense-astro-search](./typesense-astro-search) | Astro | A modern search bar with instant search capabilities | | [typesense-gin-full-text-search](./typesense-gin-full-text-search) | Go (Gin) | Backend API with full-text search using Typesense | | [typesense-next-search-bar](./typesense-next-search-bar) | Next.js | A modern search bar with instant search capabilities | +| [typesense-nuxt-search-bar](./typesense-nuxt-search-bar) | Nuxt.js | A modern search bar with instant search capabilities | | [typesense-qwik-js-search](./typesense-qwik-js-search) | Qwik | Resumable search bar with real-time search and modern UI | | [typesense-react-native-search-bar](./typesense-react-native-search-bar) | React Native | A mobile search bar with instant search capabilities | | [typesense-solid-js-search](./typesense-solid-js-search) | SolidJS | A modern search bar with instant search capabilities | diff --git a/typesense-nuxt-search-bar/.env.example b/typesense-nuxt-search-bar/.env.example new file mode 100644 index 0000000..8a12cc6 --- /dev/null +++ b/typesense-nuxt-search-bar/.env.example @@ -0,0 +1,5 @@ +NUXT_PUBLIC_TYPESENSE_API_KEY=xyz +NUXT_PUBLIC_TYPESENSE_HOST=localhost +NUXT_PUBLIC_TYPESENSE_PORT=8108 +NUXT_PUBLIC_TYPESENSE_PROTOCOL=http +NUXT_PUBLIC_TYPESENSE_INDEX=books diff --git a/typesense-nuxt-search-bar/.gitignore b/typesense-nuxt-search-bar/.gitignore new file mode 100644 index 0000000..4a7f73a --- /dev/null +++ b/typesense-nuxt-search-bar/.gitignore @@ -0,0 +1,24 @@ +# Nuxt dev/build outputs +.output +.data +.nuxt +.nitro +.cache +dist + +# Node dependencies +node_modules + +# Logs +logs +*.log + +# Misc +.DS_Store +.fleet +.idea + +# Local env files +.env +.env.* +!.env.example diff --git a/typesense-nuxt-search-bar/README.md b/typesense-nuxt-search-bar/README.md new file mode 100644 index 0000000..28572f6 --- /dev/null +++ b/typesense-nuxt-search-bar/README.md @@ -0,0 +1,115 @@ +# Nuxt.js Search Bar with Typesense + +A modern search bar application built with Nuxt.js and Typesense, featuring instant search capabilities. + +## Tech Stack + +- Nuxt.js +- Vue 3 +- Typesense +- typesense-instantsearch-adapter & vue-instantsearch +- Tailwind CSS + +## Prerequisites + +- Node.js 18+ and npm 9+. +- Docker (for running Typesense locally). Alternatively, you can use a Typesense Cloud cluster. +- Basic knowledge of Vue and Nuxt.js. + +## Quick Start + +### 1. Clone the repository + +```bash +git clone https://github.com/typesense/code-samples.git +cd code-samples/typesense-nuxt-search-bar +``` + +### 2. Install dependencies + +```bash +npm install +``` + +### 3. Set up Typesense and import data + +#### Start Typesense Server (Local Development) + +```bash +docker run -d -p 8108:8108 \ + -v/tmp/typesense-data:/data typesense/typesense:27.1 \ + --data-dir /data --api-key=xyz --enable-cors +``` + +#### Create Collection and Import Data + +The application expects a `books` collection with the following schema: + +```json +{ + "name": "books", + "fields": [ + {"name": "title", "type": "string"}, + {"name": "authors", "type": "string[]"}, + {"name": "publication_year", "type": "int32"}, + {"name": "average_rating", "type": "float"}, + {"name": "ratings_count", "type": "int32"}, + {"name": "image_url", "type": "string", "optional": true} + ] +} +``` + +### 4. Set up environment variables + +Create a `.env` file in the project root (copy from `.env.example`): + +```bash +cp .env.example .env +``` + +Update the values in `.env`: + +```env +NUXT_PUBLIC_TYPESENSE_API_KEY=xyz +NUXT_PUBLIC_TYPESENSE_HOST=localhost +NUXT_PUBLIC_TYPESENSE_PORT=8108 +NUXT_PUBLIC_TYPESENSE_PROTOCOL=http +NUXT_PUBLIC_TYPESENSE_INDEX=books +``` + +### 5. Project Structure + +```text +├── app +│ └── app.vue +├── components +│ ├── BookCard.vue +│ ├── BookList.vue +│ ├── Heading.vue +│ └── SearchBar.vue +├── types +│ └── Book.ts +├── utils +│ └── instantSearchAdapter.ts +└── nuxt.config.ts +``` + +### 5. Start the development server + +```bash +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) in your browser. + +### 6. Deployment + +Set env variables to point the app to the Typesense Cluster: + +```env +NUXT_PUBLIC_TYPESENSE_API_KEY=xxx +NUXT_PUBLIC_TYPESENSE_HOST=xxx.typesense.net +NUXT_PUBLIC_TYPESENSE_PORT=443 +NUXT_PUBLIC_TYPESENSE_PROTOCOL=https +NUXT_PUBLIC_TYPESENSE_INDEX=books +``` diff --git a/typesense-nuxt-search-bar/app/app.vue b/typesense-nuxt-search-bar/app/app.vue new file mode 100644 index 0000000..bfd3f0f --- /dev/null +++ b/typesense-nuxt-search-bar/app/app.vue @@ -0,0 +1,72 @@ + + + + + + + diff --git a/typesense-nuxt-search-bar/components/BookCard.vue b/typesense-nuxt-search-bar/components/BookCard.vue new file mode 100644 index 0000000..6be40d7 --- /dev/null +++ b/typesense-nuxt-search-bar/components/BookCard.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/typesense-nuxt-search-bar/components/BookList.vue b/typesense-nuxt-search-bar/components/BookList.vue new file mode 100644 index 0000000..fbb17c3 --- /dev/null +++ b/typesense-nuxt-search-bar/components/BookList.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/typesense-nuxt-search-bar/components/Heading.vue b/typesense-nuxt-search-bar/components/Heading.vue new file mode 100644 index 0000000..622403c --- /dev/null +++ b/typesense-nuxt-search-bar/components/Heading.vue @@ -0,0 +1,165 @@ + + + diff --git a/typesense-nuxt-search-bar/components/SearchBar.vue b/typesense-nuxt-search-bar/components/SearchBar.vue new file mode 100644 index 0000000..2ca65cf --- /dev/null +++ b/typesense-nuxt-search-bar/components/SearchBar.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/typesense-nuxt-search-bar/nuxt.config.ts b/typesense-nuxt-search-bar/nuxt.config.ts new file mode 100644 index 0000000..b2c7cae --- /dev/null +++ b/typesense-nuxt-search-bar/nuxt.config.ts @@ -0,0 +1,16 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + compatibilityDate: "2024-07-15", + devtools: { enabled: true }, + runtimeConfig: { + public: { + typesense: { + apiKey: process.env.NUXT_PUBLIC_TYPESENSE_API_KEY || "xyz", + host: process.env.NUXT_PUBLIC_TYPESENSE_HOST || "localhost", + port: parseInt(process.env.NUXT_PUBLIC_TYPESENSE_PORT || "8108", 10), + protocol: process.env.NUXT_PUBLIC_TYPESENSE_PROTOCOL || "http", + index: process.env.NUXT_PUBLIC_TYPESENSE_INDEX || "books", + }, + }, + }, +}); diff --git a/typesense-nuxt-search-bar/package.json b/typesense-nuxt-search-bar/package.json new file mode 100644 index 0000000..0ff1461 --- /dev/null +++ b/typesense-nuxt-search-bar/package.json @@ -0,0 +1,23 @@ +{ + "name": "typesense-nuxt-search-bar", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare" + }, + "dependencies": { + "nuxt": "^4.4.2", + "vue": "^3.5.30", + "vue-router": "^5.0.3", + "vue-instantsearch": "^4.20.4", + "typesense": "^2.1.0", + "typesense-instantsearch-adapter": "^2.9.0" + }, + "devDependencies": { + "@types/node": "^20" + } +} diff --git a/typesense-nuxt-search-bar/public/favicon.ico b/typesense-nuxt-search-bar/public/favicon.ico new file mode 100644 index 0000000..18993ad Binary files /dev/null and b/typesense-nuxt-search-bar/public/favicon.ico differ diff --git a/typesense-nuxt-search-bar/public/favicon.png b/typesense-nuxt-search-bar/public/favicon.png new file mode 100644 index 0000000..f42ec19 Binary files /dev/null and b/typesense-nuxt-search-bar/public/favicon.png differ diff --git a/typesense-nuxt-search-bar/public/robots.txt b/typesense-nuxt-search-bar/public/robots.txt new file mode 100644 index 0000000..0ad279c --- /dev/null +++ b/typesense-nuxt-search-bar/public/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +Disallow: diff --git a/typesense-nuxt-search-bar/tsconfig.json b/typesense-nuxt-search-bar/tsconfig.json new file mode 100644 index 0000000..307b213 --- /dev/null +++ b/typesense-nuxt-search-bar/tsconfig.json @@ -0,0 +1,18 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "files": [], + "references": [ + { + "path": "./.nuxt/tsconfig.app.json" + }, + { + "path": "./.nuxt/tsconfig.server.json" + }, + { + "path": "./.nuxt/tsconfig.shared.json" + }, + { + "path": "./.nuxt/tsconfig.node.json" + } + ] +} diff --git a/typesense-nuxt-search-bar/types/Book.ts b/typesense-nuxt-search-bar/types/Book.ts new file mode 100644 index 0000000..a60803f --- /dev/null +++ b/typesense-nuxt-search-bar/types/Book.ts @@ -0,0 +1,9 @@ +export type Book = { + id: string; + title: string; + authors: string[]; + publication_year: number; + average_rating: number; + image_url: string; + ratings_count: number; +}; diff --git a/typesense-nuxt-search-bar/utils/instantSearchAdapter.ts b/typesense-nuxt-search-bar/utils/instantSearchAdapter.ts new file mode 100644 index 0000000..c7de503 --- /dev/null +++ b/typesense-nuxt-search-bar/utils/instantSearchAdapter.ts @@ -0,0 +1,27 @@ +import TypesenseInstantsearchAdapter from "typesense-instantsearch-adapter"; + +export const createTypesenseAdapter = (config: { + apiKey: string; + host: string; + port: number; + protocol: string; +}) => { + return new TypesenseInstantsearchAdapter({ + server: { + apiKey: config.apiKey, + nodes: [ + { + host: config.host, + port: config.port, + protocol: config.protocol, + }, + ], + }, + additionalSearchParameters: { + query_by: "title,authors", + query_by_weights: "4,2", + num_typos: 1, + sort_by: "ratings_count:desc", + }, + }); +};