@todovue/tv-search 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +343 -111
- package/dist/entry.d.ts +6 -0
- package/dist/tv-search.cjs.js +45 -38
- package/dist/tv-search.d.ts +5 -0
- package/dist/tv-search.es.js +202 -167
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,63 +1,92 @@
|
|
|
1
1
|
<p align="center"><img width="150" src="https://firebasestorage.googleapis.com/v0/b/todovue-blog.appspot.com/o/logo.png?alt=media&token=d8eb592f-e4a9-4b02-8aff-62d337745f41" alt="TODOvue logo">
|
|
2
2
|
</p>
|
|
3
3
|
|
|
4
|
-
# TODOvue Search
|
|
5
|
-
|
|
4
|
+
# TODOvue Search (TvSearch)
|
|
5
|
+
A fast, accessible, and fully customizable search interface component for Vue 3 applications. Provides an elegant modal search experience with keyboard shortcuts, real-time filtering, and complete style customization. Works seamlessly in Single Page Apps or Server-Side Rendered (SSR) environments (e.g. Nuxt 3).
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/@todovue/tv-search) [](https://app.netlify.com/sites/tv-search/deploys) [](https://www.npmjs.com/package/@todovue/tv-search) [](https://www.npmjs.com/package/@todovue/tv-search) ](https://www.npmjs.com/package/@todovue/tv-search) [](https://app.netlify.com/sites/tv-search/deploys) [](https://www.npmjs.com/package/@todovue/tv-search) [](https://www.npmjs.com/package/@todovue/tv-search)  
|
|
8
8
|
|
|
9
|
+
> Demo: https://tv-search.netlify.app/
|
|
10
|
+
|
|
11
|
+
---
|
|
9
12
|
## Table of Contents
|
|
10
|
-
- [
|
|
13
|
+
- [Features](#features)
|
|
11
14
|
- [Installation](#installation)
|
|
12
|
-
- [
|
|
15
|
+
- [Quick Start (SPA)](#quick-start-spa)
|
|
16
|
+
- [Nuxt 3 / SSR Usage](#nuxt-3--ssr-usage)
|
|
17
|
+
- [Component Registration Options](#component-registration-options)
|
|
13
18
|
- [Props](#props)
|
|
14
19
|
- [Events](#events)
|
|
15
|
-
- [
|
|
20
|
+
- [Keyboard Shortcuts](#keyboard-shortcuts)
|
|
21
|
+
- [Customization (Styles / Theming)](#customization-styles--theming)
|
|
22
|
+
- [Results Data Structure](#results-data-structure)
|
|
23
|
+
- [Accessibility](#accessibility)
|
|
24
|
+
- [SSR Notes](#ssr-notes)
|
|
25
|
+
- [Roadmap](#roadmap)
|
|
16
26
|
- [Development](#development)
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [License](
|
|
27
|
+
- [Contributing](#contributing)
|
|
28
|
+
- [Changelog](#changelog)
|
|
29
|
+
- [License](#license)
|
|
20
30
|
|
|
31
|
+
---
|
|
32
|
+
## Features
|
|
33
|
+
- **Keyboard-first UX**: Open with `Ctrl+K` / `Cmd+K`, close with `Esc`
|
|
34
|
+
- **Real-time filtering**: Search as you type with instant results
|
|
35
|
+
- **Modal interface**: Clean overlay design that focuses user attention
|
|
36
|
+
- **Fully customizable**: Override colors for body, input, button, and text
|
|
37
|
+
- **Accessible**: Built with semantic HTML and keyboard navigation
|
|
38
|
+
- **Lightweight**: Minimal dependencies, Vue 3 marked as peer dependency
|
|
39
|
+
- **SSR compatible**: Works in Nuxt 3 and other SSR frameworks
|
|
40
|
+
- **Auto-focus**: Input field receives focus automatically when opened
|
|
41
|
+
- **Click-away close**: Modal closes when clicking outside the content area
|
|
42
|
+
- **Flexible results**: Pass any array of searchable items with custom properties
|
|
43
|
+
|
|
44
|
+
---
|
|
21
45
|
## Installation
|
|
22
|
-
|
|
46
|
+
Using npm:
|
|
23
47
|
```bash
|
|
24
48
|
npm install @todovue/tv-search
|
|
25
49
|
```
|
|
50
|
+
Using yarn:
|
|
26
51
|
```bash
|
|
27
52
|
yarn add @todovue/tv-search
|
|
28
53
|
```
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
54
|
+
Using pnpm:
|
|
55
|
+
```bash
|
|
56
|
+
pnpm add @todovue/tv-search
|
|
32
57
|
```
|
|
33
58
|
|
|
34
|
-
|
|
59
|
+
---
|
|
60
|
+
## Quick Start (SPA)
|
|
61
|
+
Global registration (main.js / main.ts):
|
|
35
62
|
```js
|
|
36
|
-
import { createApp } from
|
|
37
|
-
import App from
|
|
38
|
-
import TvSearch from '@todovue/tv-search'
|
|
63
|
+
import { createApp } from 'vue'
|
|
64
|
+
import App from './App.vue'
|
|
65
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
39
66
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
67
|
+
createApp(App)
|
|
68
|
+
.use(TvSearch) // enables <TvSearch /> globally
|
|
69
|
+
.mount('#app')
|
|
43
70
|
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
You can open the search component with `Ctrl + k` or `Command + k`
|
|
71
|
+
|
|
72
|
+
Alternatively, register as a component:
|
|
47
73
|
```js
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
74
|
+
import { createApp } from 'vue'
|
|
75
|
+
import App from './App.vue'
|
|
76
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
77
|
+
|
|
78
|
+
const app = createApp(App)
|
|
79
|
+
app.component('TvSearch', TvSearch)
|
|
80
|
+
app.mount('#app')
|
|
81
|
+
```
|
|
55
82
|
|
|
83
|
+
Local import inside a component:
|
|
84
|
+
```vue
|
|
56
85
|
<script setup>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
86
|
+
import { ref } from 'vue'
|
|
87
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
88
|
+
|
|
89
|
+
const results = ref([
|
|
61
90
|
{
|
|
62
91
|
id: 1,
|
|
63
92
|
title: 'How to use Vue 3',
|
|
@@ -76,115 +105,318 @@ You can open the search component with `Ctrl + k` or `Command + k`
|
|
|
76
105
|
description: 'Pinia is a modern store for Vue 3',
|
|
77
106
|
url: 'https://todovue.com/blog/how-to-use-pinia',
|
|
78
107
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
function handleSearch(query) {
|
|
111
|
+
console.log('Search query:', query)
|
|
112
|
+
// Handle search logic here
|
|
113
|
+
}
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<template>
|
|
117
|
+
<tv-search
|
|
118
|
+
placeholder="Search documentation..."
|
|
119
|
+
titleButton="Search"
|
|
120
|
+
:results="results"
|
|
121
|
+
@search="handleSearch"
|
|
122
|
+
/>
|
|
123
|
+
</template>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
## Nuxt 3 / SSR Usage
|
|
128
|
+
Create a plugin file: `plugins/tv-search.client.ts` (client-only is recommended since it uses keyboard events):
|
|
129
|
+
```ts
|
|
130
|
+
import { defineNuxtPlugin } from '#app'
|
|
131
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
132
|
+
|
|
133
|
+
export default defineNuxtPlugin(nuxtApp => {
|
|
134
|
+
nuxtApp.vueApp.component('TvSearch', TvSearch)
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Or use the plugin install method:
|
|
139
|
+
```ts
|
|
140
|
+
import { defineNuxtPlugin } from '#app'
|
|
141
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
142
|
+
|
|
143
|
+
export default defineNuxtPlugin(nuxtApp => {
|
|
144
|
+
nuxtApp.vueApp.use(TvSearch)
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Then use anywhere in your Nuxt app:
|
|
149
|
+
```vue
|
|
150
|
+
<template>
|
|
151
|
+
<tv-search
|
|
152
|
+
placeholder="Search site..."
|
|
153
|
+
titleButton="Search"
|
|
154
|
+
:results="searchResults"
|
|
155
|
+
@search="onSearch"
|
|
156
|
+
/>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script setup>
|
|
160
|
+
const searchResults = ref([
|
|
161
|
+
// your search results
|
|
162
|
+
])
|
|
163
|
+
|
|
164
|
+
function onSearch(query) {
|
|
165
|
+
// handle search
|
|
166
|
+
}
|
|
167
|
+
</script>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Optional direct import (no plugin needed):
|
|
171
|
+
```vue
|
|
172
|
+
<script setup>
|
|
173
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
92
174
|
</script>
|
|
93
175
|
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
## Component Registration Options
|
|
179
|
+
| Approach | When to use |
|
|
180
|
+
|------------------------------------------------------|----------------------------------------------------|
|
|
181
|
+
| Global via `app.use(TvSearch)` | Design system / used across many pages |
|
|
182
|
+
| Global via `app.component('TvSearch', TvSearch)` | Custom component name / multiple search components |
|
|
183
|
+
| Local named import `import TvSearch from '...'` | Single page usage / code splitting |
|
|
184
|
+
| Nuxt plugin `.client.ts` | SSR apps with client-side interactions |
|
|
185
|
+
|
|
94
186
|
---
|
|
95
187
|
## Props
|
|
96
|
-
|
|
|
97
|
-
|
|
98
|
-
|
|
|
99
|
-
| titleButton | String | `""`
|
|
100
|
-
| results | Array | `[]`
|
|
101
|
-
| customStyles | Object | [
|
|
102
|
-
|
|
103
|
-
### customStyles
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
|
107
|
-
|
|
108
|
-
|
|
|
109
|
-
|
|
|
188
|
+
| Prop | Type | Default | Description | Required |
|
|
189
|
+
|--------------|--------|---------|---------------------------------------------------------------------------------------|----------|
|
|
190
|
+
| placeholder | String | `""` | Placeholder text for the search input field | `true` |
|
|
191
|
+
| titleButton | String | `""` | Text displayed on the search button | `true` |
|
|
192
|
+
| results | Array | `[]` | Array of searchable items (see [Results Data Structure](#results-data-structure)) | `true` |
|
|
193
|
+
| customStyles | Object | `{}` | Custom color scheme for theming (see [Customization](#customization-styles--theming)) | `false` |
|
|
194
|
+
|
|
195
|
+
### customStyles Object
|
|
196
|
+
Customize the appearance by passing a `customStyles` object with any of these properties:
|
|
197
|
+
|
|
198
|
+
| Property | Type | Default | Description |
|
|
199
|
+
|-------------|--------|-------------|----------------------------------------------------------|
|
|
200
|
+
| bgBody | String | `"#0E131F"` | Background color of the modal overlay (with 0.9 opacity) |
|
|
201
|
+
| bgInput | String | `"#B9C4DF"` | Background color of the search input area |
|
|
202
|
+
| bgButton | String | `"#EF233C"` | Background color of the search button |
|
|
203
|
+
| colorButton | String | `"#F4FAFF"` | Text color of the search button |
|
|
204
|
+
|
|
110
205
|
---
|
|
111
206
|
## Events
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
| search |
|
|
207
|
+
| Event | Payload Type | Description |
|
|
208
|
+
|--------|--------------|-------------------------------------------------------------------------------------------------|
|
|
209
|
+
| search | String | Emitted when search is triggered (Enter key or button click). Returns the trimmed search query. |
|
|
115
210
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
211
|
+
Example:
|
|
212
|
+
```vue
|
|
213
|
+
<tv-search
|
|
214
|
+
placeholder="Search..."
|
|
215
|
+
titleButton="Go"
|
|
216
|
+
:results="items"
|
|
217
|
+
@search="handleSearch"
|
|
218
|
+
/>
|
|
219
|
+
|
|
220
|
+
<script setup>
|
|
221
|
+
function handleSearch(query) {
|
|
222
|
+
console.log('User searched for:', query)
|
|
223
|
+
// Perform API call, route navigation, etc.
|
|
224
|
+
}
|
|
225
|
+
</script>
|
|
125
226
|
```
|
|
126
|
-
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
## Keyboard Shortcuts
|
|
230
|
+
| Shortcut | Action |
|
|
231
|
+
|------------------------|-----------------------------------|
|
|
232
|
+
| `Ctrl + K` / `Cmd + K` | Open the search modal |
|
|
233
|
+
| `Escape` | Close the search modal |
|
|
234
|
+
| `Enter` | Execute search with current input |
|
|
235
|
+
| Click outside modal | Close the search modal |
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
## Customization (Styles / Theming)
|
|
239
|
+
You can override the default color scheme by passing a `customStyles` object:
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<script setup>
|
|
243
|
+
import { ref } from 'vue'
|
|
244
|
+
import { TvSearch } from '@todovue/tv-search'
|
|
245
|
+
|
|
246
|
+
const customStyles = ref({
|
|
247
|
+
bgBody: "#1e1d23",
|
|
248
|
+
bgInput: "#8673a1",
|
|
249
|
+
bgButton: "#80286e",
|
|
250
|
+
colorButton: "#d7c9c9",
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
const results = ref([
|
|
254
|
+
// your results
|
|
255
|
+
])
|
|
256
|
+
</script>
|
|
257
|
+
|
|
127
258
|
<template>
|
|
128
259
|
<tv-search
|
|
129
|
-
placeholder="
|
|
260
|
+
placeholder="Type to search..."
|
|
130
261
|
titleButton="Search"
|
|
131
262
|
:results="results"
|
|
132
263
|
:customStyles="customStyles"
|
|
133
264
|
/>
|
|
134
265
|
</template>
|
|
266
|
+
```
|
|
135
267
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
268
|
+
### Example Custom Themes
|
|
269
|
+
|
|
270
|
+
**Dark Theme:**
|
|
271
|
+
```js
|
|
272
|
+
const darkTheme = {
|
|
273
|
+
bgBody: "#0E131F",
|
|
274
|
+
bgInput: "#1F2937",
|
|
275
|
+
bgButton: "#3B82F6",
|
|
276
|
+
colorButton: "#FFFFFF",
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Light Theme:**
|
|
281
|
+
```js
|
|
282
|
+
const lightTheme = {
|
|
283
|
+
bgBody: "#F9FAFB",
|
|
284
|
+
bgInput: "#FFFFFF",
|
|
285
|
+
bgButton: "#6366F1",
|
|
286
|
+
colorButton: "#FFFFFF",
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Brand Theme:**
|
|
291
|
+
```js
|
|
292
|
+
const brandTheme = {
|
|
141
293
|
bgBody: "#0A4539",
|
|
142
294
|
bgInput: "#284780",
|
|
143
295
|
bgButton: "#80286E",
|
|
144
296
|
colorButton: "#D5B7B7",
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
## Results Data Structure
|
|
302
|
+
The `results` prop expects an array of objects with the following structure:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
interface SearchResult {
|
|
306
|
+
id: number | string; // Unique identifier (required for :key)
|
|
307
|
+
title: string; // Displayed in search results (required)
|
|
308
|
+
description?: string; // Additional info (optional, not currently displayed)
|
|
309
|
+
url?: string; // Navigation target (optional, not currently used in component)
|
|
310
|
+
[key: string]: any; // Any additional custom properties
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Example:
|
|
315
|
+
```js
|
|
316
|
+
const results = [
|
|
148
317
|
{
|
|
149
318
|
id: 1,
|
|
150
|
-
title: '
|
|
151
|
-
description: '
|
|
152
|
-
url: '
|
|
319
|
+
title: 'Getting Started with Vue 3',
|
|
320
|
+
description: 'Learn the basics of Vue 3 composition API',
|
|
321
|
+
url: '/docs/vue3-intro',
|
|
322
|
+
category: 'Tutorial',
|
|
153
323
|
},
|
|
154
324
|
{
|
|
155
325
|
id: 2,
|
|
156
|
-
title: '
|
|
157
|
-
description: '
|
|
158
|
-
url: '
|
|
326
|
+
title: 'Understanding Reactivity',
|
|
327
|
+
description: 'Deep dive into Vue reactivity system',
|
|
328
|
+
url: '/docs/reactivity',
|
|
329
|
+
category: 'Advanced',
|
|
159
330
|
},
|
|
160
|
-
|
|
161
|
-
id: 3,
|
|
162
|
-
title: 'Blog - How to use Pinia',
|
|
163
|
-
description: 'Pinia is a modern store for Vue 3',
|
|
164
|
-
url: 'https://todovue.com/blog/how-to-use-pinia',
|
|
165
|
-
},
|
|
166
|
-
{
|
|
167
|
-
id: 4,
|
|
168
|
-
title: 'Blog - How to use Windi CSS',
|
|
169
|
-
description: 'Windi CSS is a utility-first CSS framework',
|
|
170
|
-
url: 'https://todovue.com/blog/how-to-use-windi-css',
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
id: 5,
|
|
174
|
-
title: 'Blog - How to use Vitesse',
|
|
175
|
-
description: 'Vitesse is a Vue 3 starter template',
|
|
176
|
-
url: 'https://todovue.com/blog/how-to-use-vitesse',
|
|
177
|
-
}
|
|
178
|
-
]);
|
|
179
|
-
</script>
|
|
331
|
+
]
|
|
180
332
|
```
|
|
333
|
+
|
|
334
|
+
**Note**: The component currently filters results based on the `title` property matching the user input (case-insensitive). You can handle the `@search` event to implement custom search logic or navigation.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
## Accessibility
|
|
338
|
+
- **Keyboard navigation**: Full support for `Ctrl+K`/`Cmd+K` to open, `Esc` to close, and `Enter` to search
|
|
339
|
+
- **Focus management**: Input automatically receives focus when modal opens and is selected for immediate typing
|
|
340
|
+
- **Semantic HTML**: Uses proper `<button>`, `<input>`, and modal structure
|
|
341
|
+
- **Click-away**: Modal closes when clicking the overlay, providing intuitive UX
|
|
342
|
+
|
|
343
|
+
**Recommendations:**
|
|
344
|
+
- Provide clear, descriptive `placeholder` text
|
|
345
|
+
- Use meaningful `titleButton` text (e.g., "Search", "Find", "Go")
|
|
346
|
+
- Ensure sufficient color contrast when using `customStyles`
|
|
347
|
+
- Consider adding `aria-label` attributes for screen reader support in future versions
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
## SSR Notes
|
|
351
|
+
- **Safe for SSR**: No direct DOM access (`window` / `document`) during module initialization
|
|
352
|
+
- **Event listeners**: Keyboard event listeners are registered in `onMounted` and cleaned up in `onBeforeUnmount`
|
|
353
|
+
- **Client-side only**: Keyboard shortcuts require browser environment; use `.client.ts` plugin in Nuxt
|
|
354
|
+
- **Icons**: SVG icons are loaded via Vite's `import.meta.glob`, which works in both SPA and SSR builds
|
|
355
|
+
- **No manual CSS import required**: Styles are automatically injected via `vite-plugin-css-injected-by-js`
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
## Roadmap
|
|
359
|
+
| Feature | Status |
|
|
360
|
+
|------------------------------------------|-------------|
|
|
361
|
+
| Support for result `url` navigation | Planned |
|
|
362
|
+
| Display `description` in results | Planned |
|
|
363
|
+
| Customizable search icon | Planned |
|
|
364
|
+
| Multiple keyboard shortcut options | Considering |
|
|
365
|
+
| Result categorization / grouping | Considering |
|
|
366
|
+
| Highlight matching text in results | Considering |
|
|
367
|
+
| Recent searches history | Considering |
|
|
368
|
+
| Loading state indicator | Considering |
|
|
369
|
+
| Pagination for large result sets | Considering |
|
|
370
|
+
| Fuzzy search / advanced filtering | Considering |
|
|
371
|
+
| Theming via CSS variables | Considering |
|
|
372
|
+
| TypeScript type definitions improvement | Planned |
|
|
373
|
+
| ARIA attributes enhancement | Planned |
|
|
374
|
+
|
|
375
|
+
---
|
|
181
376
|
## Development
|
|
182
|
-
Clone the repository and install
|
|
377
|
+
Clone the repository and install dependencies:
|
|
183
378
|
```bash
|
|
184
379
|
git clone https://github.com/TODOvue/tv-search.git
|
|
185
380
|
cd tv-search
|
|
186
381
|
yarn install
|
|
187
382
|
```
|
|
383
|
+
|
|
384
|
+
Run development server with demo playground:
|
|
385
|
+
```bash
|
|
386
|
+
yarn dev
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Build the library:
|
|
390
|
+
```bash
|
|
391
|
+
yarn build
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Build demo site:
|
|
395
|
+
```bash
|
|
396
|
+
yarn build:demo
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
The demo is served from Vite using `index.html` + `src/demo` examples.
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
## Contributing
|
|
403
|
+
Contributions are welcome! Please read our [Contributing Guidelines](https://github.com/TODOvue/tv-search/blob/main/CONTRIBUTING.md) and [Code of Conduct](https://github.com/TODOvue/tv-search/blob/main/CODE_OF_CONDUCT.md) before submitting PRs.
|
|
404
|
+
|
|
405
|
+
**How to contribute:**
|
|
406
|
+
1. Fork the repository
|
|
407
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
408
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
409
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
410
|
+
5. Open a Pull Request
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
## Changelog
|
|
414
|
+
See [CHANGELOG.md](https://github.com/TODOvue/tv-search/blob/main/CHANGELOG.md) for release history and version changes.
|
|
415
|
+
|
|
188
416
|
---
|
|
189
417
|
## License
|
|
190
|
-
[MIT](https://github.com/TODOvue/tv-search/blob/main/LICENSE)
|
|
418
|
+
[MIT](https://github.com/TODOvue/tv-search/blob/main/LICENSE) © TODOvue
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
### Attributions
|
|
422
|
+
Crafted for the TODOvue component ecosystem
|