@todovue/tv-ui 0.1.0 → 0.1.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.
Files changed (48) hide show
  1. package/README.md +20 -20
  2. package/dist/entry.d.ts +2 -2
  3. package/dist/tv-ui.cjs.js +1 -1
  4. package/dist/tv-ui.css +1 -1
  5. package/dist/tv-ui.es.js +50 -49
  6. package/package.json +4 -2
  7. package/dist/.htaccess +0 -8
  8. package/dist/demos/tv-alert/CHANGELOG.md +0 -127
  9. package/dist/demos/tv-alert/README.md +0 -334
  10. package/dist/demos/tv-article/CHANGELOG.md +0 -221
  11. package/dist/demos/tv-article/README.md +0 -258
  12. package/dist/demos/tv-breadcrumbs/CHANGELOG.md +0 -135
  13. package/dist/demos/tv-breadcrumbs/README.md +0 -364
  14. package/dist/demos/tv-button/CHANGELOG.md +0 -158
  15. package/dist/demos/tv-button/README.md +0 -255
  16. package/dist/demos/tv-card/CHANGELOG.md +0 -158
  17. package/dist/demos/tv-card/README.md +0 -332
  18. package/dist/demos/tv-demo/CHANGELOG.md +0 -352
  19. package/dist/demos/tv-demo/README.md +0 -229
  20. package/dist/demos/tv-footer/CHANGELOG.md +0 -67
  21. package/dist/demos/tv-footer/README.md +0 -760
  22. package/dist/demos/tv-hero/CHANGELOG.md +0 -137
  23. package/dist/demos/tv-hero/README.md +0 -410
  24. package/dist/demos/tv-label/CHANGELOG.md +0 -138
  25. package/dist/demos/tv-label/README.md +0 -357
  26. package/dist/demos/tv-menu/CHANGELOG.md +0 -145
  27. package/dist/demos/tv-menu/README.md +0 -389
  28. package/dist/demos/tv-modal/CHANGELOG.md +0 -127
  29. package/dist/demos/tv-modal/README.md +0 -466
  30. package/dist/demos/tv-pagination/CHANGELOG.md +0 -125
  31. package/dist/demos/tv-pagination/README.md +0 -275
  32. package/dist/demos/tv-progress-bar/CHANGELOG.md +0 -84
  33. package/dist/demos/tv-progress-bar/README.md +0 -894
  34. package/dist/demos/tv-relative-time/CHANGELOG.md +0 -122
  35. package/dist/demos/tv-relative-time/README.md +0 -405
  36. package/dist/demos/tv-scroll-top/CHANGELOG.md +0 -69
  37. package/dist/demos/tv-scroll-top/README.md +0 -445
  38. package/dist/demos/tv-search/CHANGELOG.md +0 -155
  39. package/dist/demos/tv-search/README.md +0 -407
  40. package/dist/demos/tv-settings/CHANGELOG.md +0 -94
  41. package/dist/demos/tv-settings/README.md +0 -314
  42. package/dist/demos/tv-sidebar/CHANGELOG.md +0 -229
  43. package/dist/demos/tv-sidebar/README.md +0 -592
  44. package/dist/demos/tv-theme-button/CHANGELOG.md +0 -136
  45. package/dist/demos/tv-theme-button/README.md +0 -392
  46. package/dist/demos/tv-toc/CHANGELOG.md +0 -80
  47. package/dist/demos/tv-toc/README.md +0 -288
  48. package/dist/favicon.ico +0 -0
@@ -1,592 +0,0 @@
1
- <p align="center"><img width="150" src="https://res.cloudinary.com/dcdfhi8qz/image/upload/v1763663056/uqqtkgp1lg3xdplutpga.png" alt="TODOvue logo">
2
- </p>
3
-
4
- # TODOvue Sidebar (TvSidebar)
5
- A versatile and flexible Vue 3 sidebar component with multiple display modes: lists, categories (labels), and images. Perfect for blogs, documentation sites, and web applications requiring sidebar navigation or content display. Compatible with both SPA and SSR environments (e.g. Nuxt 3).
6
-
7
- [![npm](https://img.shields.io/npm/v/@todovue/tv-sidebar.svg)](https://www.npmjs.com/package/@todovue/tv-sidebar)
8
- [![npm downloads](https://img.shields.io/npm/dm/@todovue/tv-sidebar.svg)](https://www.npmjs.com/package/@todovue/tv-sidebar)
9
- [![npm total downloads](https://img.shields.io/npm/dt/@todovue/tv-sidebar.svg)](https://www.npmjs.com/package/@todovue/tv-sidebar)
10
- ![License](https://img.shields.io/github/license/TODOvue/tv-sidebar)
11
- ![Release Date](https://img.shields.io/github/release-date/TODOvue/tv-sidebar)
12
- ![Bundle Size](https://img.shields.io/bundlephobia/minzip/@todovue/tv-sidebar)
13
- ![Node Version](https://img.shields.io/node/v/@todovue/tv-sidebar)
14
- ![Last Commit](https://img.shields.io/github/last-commit/TODOvue/tv-sidebar)
15
- ![Stars](https://img.shields.io/github/stars/TODOvue/tv-sidebar?style=social)
16
-
17
- > Demo: https://ui.todovue.blog/sidebar
18
-
19
- ## Table of Contents
20
- - [Features](#features)
21
- - [Installation](#installation)
22
- - [Quick Start (SPA)](#quick-start-spa)
23
- - [Nuxt 4 / SSR Usage](#nuxt-4--ssr-usage)
24
- - [Component Registration Options](#component-registration-options)
25
- - [Props](#props)
26
- - [Events](#events)
27
- - [Usage Examples](#usage-examples)
28
- - [Default List Mode](#default-list-mode)
29
- - [Categories (Labels) Mode](#categories-labels-mode)
30
- - [Image Mode](#image-mode)
31
- - [With Limit](#with-limit)
32
- - [Data Structure](#data-structure)
33
- - [Styling](#styling)
34
- - [Navigation Handling](#navigation-handling)
35
- - [Accessibility](#accessibility)
36
- - [SSR Notes](#ssr-notes)
37
- - [Development](#development)
38
- - [Contributing](#contributing)
39
- - [License](#license)
40
-
41
- ## Features
42
- - **Four display modes**: List, Categories (labels), Image, and Grouped/Categorized
43
- - **Hierarchical grouping**: Organize content with collapsible sections and item counters
44
- - **Event-driven interactions**: No built-in navigation; emits click events with full objects
45
- - **Item limit**: Control how many items to display with the `limit` prop
46
- - **Search/Filter**: Real-time filtering across all display modes including grouped content
47
- - **Optional clickable images**: Enable with `clickable` to emit click events for images
48
- - **Label/Category support**: Display colored category labels with click events
49
- - **Responsive design**: Adapts to different screen sizes
50
- - **SSR compatible**: Works seamlessly in Nuxt 3 and SSR contexts
51
- - **Customizable styling**: Built with SCSS for easy theming
52
- - **Tree-shakeable**: Vue marked as external dependency
53
-
54
- ## Installation
55
- Using npm:
56
- ```bash
57
- npm install @todovue/tv-sidebar
58
- ```
59
- Using yarn:
60
- ```bash
61
- yarn add @todovue/tv-sidebar
62
- ```
63
- Using pnpm:
64
- ```bash
65
- pnpm add @todovue/tv-sidebar
66
- ```
67
-
68
- > **Note**: This component depends on `@todovue/tv-label` for the categories mode.
69
-
70
- ## Quick Start (SPA)
71
- Global registration (main.js / main.ts):
72
- ```js
73
- import { createApp } from 'vue'
74
- import App from './App.vue'
75
- import TvSidebar from '@todovue/tv-sidebar'
76
- import '@todovue/tv-sidebar/style.css' // import styles
77
- import '@todovue/tv-label/style.css' // import styles
78
-
79
- createApp(App)
80
- .use(TvSidebar) // enables <TvSidebar /> globally
81
- .mount('#app')
82
- ```
83
- Local import inside a component:
84
- ```vue
85
- <script setup>
86
- import { TvSidebar } from '@todovue/tv-sidebar'
87
- import '@todovue/tv-sidebar/style.css' // import styles
88
- import '@todovue/tv-label/style.css' // import styles
89
-
90
- const sidebarData = {
91
- title: "Most Popular Blogs",
92
- list: [
93
- {
94
- id: 1,
95
- title: "10 Tips for Creating a Successful YouTube Channel",
96
- link: "/blog/youtube-tips",
97
- },
98
- {
99
- id: 2,
100
- title: "The Benefits of Meditation",
101
- link: "/blog/meditation",
102
- }
103
- ]
104
- }
105
- </script>
106
-
107
- <template>
108
- <TvSidebar :data="sidebarData" />
109
- </template>
110
- ```
111
-
112
- ## Nuxt 4 / SSR Usage
113
- Add the stylesheet to your `nuxt.config.ts`:
114
- ```ts
115
- // nuxt.config.ts
116
- export default defineNuxtConfig({
117
- modules: [
118
- '@todovue/tv-card/nuxt'
119
- ]
120
- })
121
- ```
122
-
123
- Create a plugin file: `plugins/tv-sidebar.client.ts` (or without `.client` suffix for SSR):
124
- ```ts
125
- import { defineNuxtPlugin } from '#app'
126
- import TvSidebar from '@todovue/tv-sidebar'
127
-
128
- export default defineNuxtPlugin(nuxtApp => {
129
- nuxtApp.vueApp.use(TvSidebar)
130
- })
131
- ```
132
- Use anywhere (no router dependency required):
133
- ```vue
134
- <script setup>
135
- import { TvSidebar } from '@todovue/tv-sidebar'
136
- </script>
137
- ```
138
-
139
- ## Component Registration Options
140
- | Approach | When to use |
141
- |---------------------------------------------------------------------|------------------------------------------------|
142
- | Global via `app.use(TvSidebar)` | Many usages across app / design system install |
143
- | Local named import `{ TvSidebar }` | Isolated / code-split contexts |
144
- | Direct default import `import TvSidebar from '@todovue/tv-sidebar'` | Single usage or manual registration |
145
-
146
- ## Props
147
- | Prop | Type | Default | Description |
148
- |-------------------|---------|---------------|------------------------------------------------------------------------------------------------------------------------------------------|
149
- | data | Object | `{}` | Main data object containing title and content (list, labels, or image). |
150
- | isImage | Boolean | `false` | Enables image display mode. |
151
- | isLabel | Boolean | `false` | Enables categories/labels display mode. |
152
- | isOutline | Boolean | `false` | Apply outline style to labels (only works with `isLabel`). |
153
- | size | String | `'md'` | Sets size of labels (`sm`, `md`, `lg`). Only works with `isLabel`. |
154
- | limit | Number | `0` | Maximum number of items to display (0 = show all). |
155
- | clickable | Boolean | `false` | When `true` and `isImage`, the image becomes interactive and emits a `click` event with the image object. When `false`, image is static. |
156
- | searchable | Boolean | `false` | Enables search/filter input for filtering items in real-time across all display modes. |
157
- | searchPlaceholder | String | `'Search...'` | Placeholder text for the search input field. |
158
- | grouped | Boolean | `false` | Enables grouped/categorized mode with collapsible sections. Requires `data.groups` array instead of `data.list` or `data.labels`. |
159
- | newLabelText | String | `'New'` | Text to display in the "New" badge when `isNew` is true on an item. |
160
- | newLabelColor | String | `'#FF3B30'` | Hex color code for the "New" badge background. |
161
-
162
- ## Events
163
- | Event name (kebab) | Emits (camel) | Description |
164
- |--------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
165
- | `click` | `click` | Emitted when a list item is clicked, when a label is clicked, and when an image is clicked (if `clickable`). The payload is always the full object. |
166
- | `search` | `search` | Emitted when the search query changes. The payload is the search string. |
167
-
168
- Usage:
169
- ```vue
170
- <TvSidebar
171
- isLabel
172
- searchable
173
- :data="categoriesData"
174
- @click="handleAnyClick"
175
- @search="handleSearch"
176
- />
177
- ```
178
-
179
- ## Usage Examples
180
-
181
- ### Default List Mode
182
- Display a numbered list of items that emit the full object on click:
183
- ```vue
184
- <script setup>
185
- import { TvSidebar } from '@todovue/tv-sidebar'
186
-
187
- const listData = {
188
- title: "Most Popular Blogs",
189
- list: [
190
- {id: 1, title: "10 Tips for Creating a Successful YouTube Channel", link: "/blog/youtube-tips"},
191
- {id: 2, title: "The Benefits of Meditation and How to Get Started", link: "/blog/meditation"},
192
- {id: 3, title: "The Top 5 Destinations for Adventure Travel", link: "/blog/adventure-travel"}
193
- ],
194
- }
195
- function handleItemClick(item) {
196
- console.log('Item clicked:', item)
197
- }
198
- </script>
199
-
200
- <template>
201
- <TvSidebar :data="listData" @click="handleItemClick" />
202
- </template>
203
- ```
204
-
205
- ### Categories (Labels) Mode
206
- Display colored category labels:
207
- ```vue
208
- <script setup>
209
- import { TvSidebar } from '@todovue/tv-sidebar'
210
-
211
- const categoriesData = {
212
- title: "Categories",
213
- labels: [
214
- {
215
- id: 1,
216
- name: "Vue.js",
217
- color: "#4FC08D",
218
- },
219
- {
220
- id: 2,
221
- name: "JavaScript",
222
- color: "#F0DB4F",
223
- },
224
- {
225
- id: 3,
226
- name: "HTML",
227
- color: "#E34F26",
228
- },
229
- {
230
- id: 4,
231
- name: "CSS",
232
- color: "#1572B6",
233
- }
234
- ]
235
- }
236
-
237
- function handleCategoryClick(category) {
238
- console.log('Category clicked:', category)
239
- // Navigate or filter by category
240
- }
241
- </script>
242
-
243
- <template>
244
- <TvSidebar
245
- isLabel
246
- :data="categoriesData"
247
- @clickLabel="handleCategoryClick"
248
- />
249
- </template>
250
- ```
251
-
252
- ### Image Mode
253
- Display an image with title. Make it interactive with `clickable` if desired:
254
- ```vue
255
- <script setup>
256
- import { TvSidebar } from '@todovue/tv-sidebar'
257
-
258
- const imageData = {
259
- title: "TODOvue Blog",
260
- image: {
261
- src: "https://todovue.com/vue.webp",
262
- alt: "TODOvue Logo",
263
- link: "https://todovue.com/"
264
- },
265
- }
266
- function handleImageClick(image) {
267
- console.log('Image clicked:', image)
268
- }
269
- </script>
270
-
271
- <template>
272
- <!-- Non-clickable image -->
273
- <TvSidebar isImage :data="imageData" />
274
-
275
- <!-- Clickable image that emits the image object -->
276
- <TvSidebar isImage clickable :data="imageData" @click="handleImageClick" />
277
- </template>
278
- ```
279
-
280
- ### With Limit
281
- Limit the number of displayed items:
282
- ```vue
283
- <template>
284
- <!-- Show only first 5 items -->
285
- <TvSidebar :data="listData" :limit="5" />
286
-
287
- <!-- Show only first 8 categories -->
288
- <TvSidebar isLabel :data="categoriesData" :limit="8" />
289
- </template>
290
- ```
291
-
292
- ### With Search/Filter
293
- Enable real-time search and filtering across all display modes:
294
- ```vue
295
- <script setup>
296
- import { TvSidebar } from '@todovue/tv-sidebar'
297
-
298
- const listData = {
299
- title: 'Blog Posts',
300
- list: [
301
- { id: 1, title: 'Getting Started with Vue 3', link: '/blog/vue-3' },
302
- { id: 2, title: 'Understanding Composition API', link: '/blog/composition-api' },
303
- { id: 3, title: 'Building Reactive Forms', link: '/blog/reactive-forms' }
304
- ]
305
- }
306
-
307
- const categoriesData = {
308
- title: 'Categories',
309
- labels: [
310
- { id: 1, name: 'Vue.js', color: '#4FC08D' },
311
- { id: 2, name: 'JavaScript', color: '#F0DB4F' },
312
- { id: 3, name: 'TypeScript', color: '#007ACC' }
313
- ]
314
- }
315
-
316
- function handleSearch(query) {
317
- console.log('Search query:', query)
318
- // Optionally perform additional actions
319
- }
320
- </script>
321
-
322
- <template>
323
- <!-- Searchable list with default placeholder -->
324
- <TvSidebar
325
- :data="listData"
326
- searchable
327
- @search="handleSearch"
328
- />
329
-
330
- <!-- Searchable labels with custom placeholder -->
331
- <TvSidebar
332
- isLabel
333
- :data="categoriesData"
334
- searchable
335
- search-placeholder="Filter categories..."
336
- @search="handleSearch"
337
- />
338
-
339
- <!-- Searchable with limit (filtering applied before limiting) -->
340
- <TvSidebar
341
- :data="listData"
342
- searchable
343
- :limit="5"
344
- />
345
- </template>
346
- ```
347
-
348
- ### Grouped/Categorized Mode
349
- Organize content hierarchically with collapsible groups and item counters:
350
- ```vue
351
- <script setup>
352
- import { TvSidebar } from '@todovue/tv-sidebar'
353
-
354
- const groupedData = {
355
- title: 'Blog Posts',
356
- groups: [
357
- {
358
- id: 1,
359
- name: 'Technical',
360
- collapsed: false,
361
- items: [
362
- { id: 1, title: '10 Tips for Creating a Successful YouTube Channel', link: '/blog/youtube' },
363
- { id: 2, title: 'How to Create High-Quality Visual Content', link: '/blog/visual-content' },
364
- { id: 3, title: 'The Power of Email Marketing', link: '/blog/email-marketing' }
365
- ]
366
- },
367
- {
368
- id: 2,
369
- name: 'Lifestyle',
370
- collapsed: true,
371
- items: [
372
- { id: 4, title: 'Why You Should Consider a Plant-Based Diet', link: '/blog/plant-based' },
373
- { id: 5, title: 'The Pros and Cons of Remote Work', link: '/blog/remote-work' }
374
- ]
375
- },
376
- {
377
- id: 3,
378
- name: 'Travel',
379
- collapsed: false,
380
- items: [
381
- { id: 6, title: 'The Top 5 Destinations for Adventure Travel', link: '/blog/adventure' }
382
- ]
383
- }
384
- ]
385
- }
386
-
387
- function handleItemClick(item) {
388
- console.log('Item clicked:', item)
389
- }
390
- </script>
391
-
392
- <template>
393
- <!-- Basic grouped mode -->
394
- <TvSidebar
395
- grouped
396
- :data="groupedData"
397
- @click="handleItemClick"
398
- />
399
-
400
- <!-- Grouped mode with search -->
401
- <TvSidebar
402
- grouped
403
- searchable
404
- search-placeholder="Search posts..."
405
- :data="groupedData"
406
- @click="handleItemClick"
407
- />
408
-
409
- <!-- Grouped mode with limit (applies to items per group) -->
410
- <TvSidebar
411
- grouped
412
- :limit="2"
413
- :data="groupedData"
414
- @click="handleItemClick"
415
- />
416
- </template>
417
- ```
418
-
419
- ### New Items Indicator
420
- Mark items as new by adding `isNew: true` to the item object. Customize the label text with `newLabelText`.
421
-
422
- ```vue
423
- <script setup>
424
- import { TvSidebar } from '@todovue/tv-sidebar'
425
-
426
- const listData = {
427
- title: "Updates",
428
- list: [
429
- { id: 1, title: "Stable Release", link: "/v1", isNew: true },
430
- { id: 2, title: "Beta Release", link: "/beta" }
431
- ]
432
- }
433
- </script>
434
-
435
- <template>
436
- <TvSidebar :data="listData" new-label-text="UPDATED" />
437
- </template>
438
- ```
439
- ```
440
-
441
- ### Nuxt Integration
442
- ```diff
443
- - Using with Nuxt routing:
444
- - <TvSidebar linkTag="nuxt-link" :data="blogPosts" />
445
- ```
446
- Nuxt works without router integration in the component. Handle navigation in your click handlers (see Navigation Handling below).
447
-
448
- ## Data Structure
449
-
450
- ### List Mode Data
451
- ```typescript
452
- {
453
- title: string,
454
- list: Array<{
455
- id: number | string,
456
- title: string,
457
- link?: string, // optional; use in your click handler if you want to navigate
458
- isNew?: boolean // optional; displays a 'New' badge
459
- }>
460
- }
461
- ```
462
-
463
- ### Labels/Categories Mode Data
464
- ```typescript
465
- {
466
- title: string,
467
- labels: Array<{
468
- id: number | string,
469
- name: string,
470
- color: string // Hex color code
471
- }>
472
- }
473
- ```
474
-
475
- ### Image Mode Data
476
- ```typescript
477
- {
478
- title: string,
479
- image: {
480
- src: string, // Image URL
481
- alt: string, // Alt text for accessibility
482
- link?: string // optional; use in your click handler for manual navigation
483
- }
484
- }
485
- ```
486
-
487
- ### Grouped Mode Data
488
- ```typescript
489
- {
490
- title: string,
491
- groups: Array<{
492
- id: number | string,
493
- name: string, // Group/category name
494
- collapsed: boolean, // Initial collapsed state
495
- items: Array<{
496
- id: number | string,
497
- title: string,
498
- link?: string, // optional; use in your click handler if you want to navigate
499
- isNew?: boolean // optional; displays a 'New' badge
500
- }>
501
- }>
502
- }
503
- ```
504
-
505
- ## Styling
506
- The component uses SCSS for styling. Styles are automatically included when you import the component. The sidebar includes:
507
- - Clean, minimal design
508
- - Responsive layout
509
- - Title with separator line
510
- - Hover effects on interactive items
511
- - Proper spacing and typography
512
-
513
- To customize styles, you can override the CSS classes:
514
- ```css
515
- .tv-sidebar-body {
516
- /* Container styles */
517
- }
518
-
519
- .tv-sidebar {
520
- /* Main sidebar styles */
521
- }
522
-
523
- .tv-sidebar-title h1 {
524
- /* Title styles */
525
- }
526
-
527
- .tv-sidebar-content-li {
528
- /* List item styles */
529
- }
530
- ```
531
-
532
- ## Navigation Handling
533
- Since the component does not perform navigation, handle it in your click handlers. Example with Vue Router:
534
- ```vue
535
- <script setup>
536
- import { TvSidebar } from '@todovue/tv-sidebar'
537
- import { useRouter } from 'vue-router'
538
-
539
- const router = useRouter()
540
-
541
- const listData = {
542
- title: 'Recent Posts',
543
- list: [
544
- { id: 1, title: 'Getting Started with Nuxt 3', link: '/blog/nuxt-3' },
545
- { id: 2, title: 'Vue Composition API', link: '/blog/composition-api' }
546
- ]
547
- }
548
-
549
- function handleClick(item) {
550
- if (item?.link) router.push(item.link)
551
- }
552
- </script>
553
-
554
- <template>
555
- <TvSidebar :data="listData" @click="handleClick" />
556
- </template>
557
- ```
558
-
559
- ## Accessibility
560
- - Semantic structure with clear headings
561
- - Alt text support for images
562
- - Interactive items emit click events; if you need keyboard accessibility, consider handling `keydown` (Enter/Space) on your side or wrapping with accessible elements/roles
563
- - Color contrast considerations for labels
564
-
565
- ## SSR Notes
566
- - No direct DOM access (`window` / `document`) → safe for SSR
567
- - Compatible with Nuxt 3 out of the box
568
- - Styles are bundled and auto-imported
569
- - No router/nuxt-link dependency inside the component
570
-
571
- ## Development
572
- ```bash
573
- git clone https://github.com/TODOvue/tv-sidebar.git
574
- cd tv-sidebar
575
- npm install
576
- npm run dev # run demo playground
577
- npm run build # build library
578
- ```
579
- Local demo served from Vite using `index.html` + `src/demo` examples.
580
-
581
- ## Contributing
582
- PRs and issues welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
583
-
584
- ## License
585
- MIT © TODOvue
586
-
587
- ## Dependencies
588
- - `vue` (^3.0.0) - Peer dependency
589
- - `@todovue/tv-label` - Used for category/label display mode
590
-
591
- ### Attributions
592
- Crafted with ❤️ for the TODOvue component ecosystem by Cristhian Daza