@todovue/tv-ui 0.1.0

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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/dist/.htaccess +8 -0
  4. package/dist/demos/tv-alert/CHANGELOG.md +127 -0
  5. package/dist/demos/tv-alert/README.md +334 -0
  6. package/dist/demos/tv-article/CHANGELOG.md +221 -0
  7. package/dist/demos/tv-article/README.md +258 -0
  8. package/dist/demos/tv-breadcrumbs/CHANGELOG.md +135 -0
  9. package/dist/demos/tv-breadcrumbs/README.md +364 -0
  10. package/dist/demos/tv-button/CHANGELOG.md +158 -0
  11. package/dist/demos/tv-button/README.md +255 -0
  12. package/dist/demos/tv-card/CHANGELOG.md +158 -0
  13. package/dist/demos/tv-card/README.md +332 -0
  14. package/dist/demos/tv-demo/CHANGELOG.md +352 -0
  15. package/dist/demos/tv-demo/README.md +229 -0
  16. package/dist/demos/tv-footer/CHANGELOG.md +67 -0
  17. package/dist/demos/tv-footer/README.md +760 -0
  18. package/dist/demos/tv-hero/CHANGELOG.md +137 -0
  19. package/dist/demos/tv-hero/README.md +410 -0
  20. package/dist/demos/tv-label/CHANGELOG.md +138 -0
  21. package/dist/demos/tv-label/README.md +357 -0
  22. package/dist/demos/tv-menu/CHANGELOG.md +145 -0
  23. package/dist/demos/tv-menu/README.md +389 -0
  24. package/dist/demos/tv-modal/CHANGELOG.md +127 -0
  25. package/dist/demos/tv-modal/README.md +466 -0
  26. package/dist/demos/tv-pagination/CHANGELOG.md +125 -0
  27. package/dist/demos/tv-pagination/README.md +275 -0
  28. package/dist/demos/tv-progress-bar/CHANGELOG.md +84 -0
  29. package/dist/demos/tv-progress-bar/README.md +894 -0
  30. package/dist/demos/tv-relative-time/CHANGELOG.md +122 -0
  31. package/dist/demos/tv-relative-time/README.md +405 -0
  32. package/dist/demos/tv-scroll-top/CHANGELOG.md +69 -0
  33. package/dist/demos/tv-scroll-top/README.md +445 -0
  34. package/dist/demos/tv-search/CHANGELOG.md +155 -0
  35. package/dist/demos/tv-search/README.md +407 -0
  36. package/dist/demos/tv-settings/CHANGELOG.md +94 -0
  37. package/dist/demos/tv-settings/README.md +314 -0
  38. package/dist/demos/tv-sidebar/CHANGELOG.md +229 -0
  39. package/dist/demos/tv-sidebar/README.md +592 -0
  40. package/dist/demos/tv-theme-button/CHANGELOG.md +136 -0
  41. package/dist/demos/tv-theme-button/README.md +392 -0
  42. package/dist/demos/tv-toc/CHANGELOG.md +80 -0
  43. package/dist/demos/tv-toc/README.md +288 -0
  44. package/dist/entry.d.ts +48 -0
  45. package/dist/favicon.ico +0 -0
  46. package/dist/tv-ui.cjs.js +1 -0
  47. package/dist/tv-ui.css +1 -0
  48. package/dist/tv-ui.d.ts +6 -0
  49. package/dist/tv-ui.es.js +92 -0
  50. package/nuxt.js +58 -0
  51. package/package.json +92 -0
@@ -0,0 +1,760 @@
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 Footer (TvFooter)
5
+ A simple, customizable, and responsive Vue 3 footer component with support for branding, navigation sections, social links, legal links, and SSR compatibility. Perfect for building professional footers in Single Page Apps and Server-Side Rendered environments like Nuxt 3.
6
+
7
+ [![npm](https://img.shields.io/npm/v/@todovue/tv-footer.svg)](https://www.npmjs.com/package/@todovue/tv-footer)
8
+ [![npm downloads](https://img.shields.io/npm/dm/@todovue/tv-footer.svg)](https://www.npmjs.com/package/@todovue/tv-footer)
9
+ [![npm total downloads](https://img.shields.io/npm/dt/@todovue/tv-footer.svg)](https://www.npmjs.com/package/@todovue/tv-footer)
10
+ ![License](https://img.shields.io/github/license/TODOvue/tv-footer)
11
+ ![Release Date](https://img.shields.io/github/release-date/TODOvue/tv-footer)
12
+ ![Bundle Size](https://img.shields.io/bundlephobia/minzip/@todovue/tv-footer)
13
+ ![Node Version](https://img.shields.io/node/v/@todovue/tv-footer)
14
+ ![Last Commit](https://img.shields.io/github/last-commit/TODOvue/tv-footer)
15
+ ![Stars](https://img.shields.io/github/stars/TODOvue/tv-footer?style=social)
16
+
17
+ > Demo: https://ui.todovue.blog/footer
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
+ - [Configuration Object](#configuration-object)
27
+ - [Composable API](#composable-api)
28
+ - [Usage Examples](#usage-examples)
29
+ - [Styling](#styling)
30
+ - [Accessibility](#accessibility)
31
+ - [SSR Notes](#ssr-notes)
32
+ - [Development](#development)
33
+ - [Contributing](#contributing)
34
+ - [License](#license)
35
+
36
+ ## Features
37
+ - Fully responsive grid layout (1 column on mobile, 2 on tablet, 4 on desktop)
38
+ - Customizable brand section with logo and version display
39
+ - Multiple navigation sections with titles and links
40
+ - Social media links with icon support
41
+ - Legal links section (Privacy, Terms, etc.)
42
+ - Dynamic copyright with automatic year replacement
43
+ - Light/Dark mode support built-in
44
+ - SSR-safe (works with Nuxt 3 and other SSR frameworks)
45
+ - Composable API (`useFooter`) for custom implementations
46
+ - Accessible and semantic HTML
47
+ - Lightweight and tree-shakeable
48
+ - TypeScript support
49
+
50
+ ## Installation
51
+ Using npm:
52
+ ```bash
53
+ npm install @todovue/tv-footer
54
+ ```
55
+ Using yarn:
56
+ ```bash
57
+ yarn add @todovue/tv-footer
58
+ ```
59
+ Using pnpm:
60
+ ```bash
61
+ pnpm add @todovue/tv-footer
62
+ ```
63
+
64
+ ### Importing Styles
65
+ **Important:** You must explicitly import the stylesheet in your application.
66
+
67
+ #### For Vue/Vite SPA:
68
+ ```ts
69
+ // main.ts
70
+ import { createApp } from 'vue'
71
+ import App from './App.vue'
72
+
73
+ import '@todovue/tv-footer/style.css'
74
+ import { TvFooter } from '@todovue/tv-footer'
75
+
76
+ const app = createApp(App)
77
+ app.component('TvFooter', TvFooter)
78
+ app.mount('#app')
79
+ ```
80
+
81
+ #### For Nuxt 3/4:
82
+ ```ts
83
+ // nuxt.config.ts
84
+ export default defineNuxtConfig({
85
+ modules: [
86
+ '@todovue/tv-footer/nuxt'
87
+ ]
88
+ })
89
+ ```
90
+
91
+ Then register the component in a plugin as shown in the [Nuxt 3 / SSR Usage](#nuxt-3--ssr-usage) section.
92
+
93
+ ## Quick Start (SPA)
94
+ Global registration (main.js / main.ts):
95
+ ```js
96
+ import { createApp } from 'vue'
97
+ import App from './App.vue'
98
+ import '@todovue/tv-footer/style.css'
99
+ import TvFooter from '@todovue/tv-footer'
100
+
101
+ createApp(App)
102
+ .use(TvFooter) // enables <TvFooter /> globally
103
+ .mount('#app')
104
+ ```
105
+ Local import inside a component:
106
+ ```vue
107
+ <script setup>
108
+ import { TvFooter } from '@todovue/tv-footer'
109
+ import '@todovue/tv-footer/style.css'
110
+
111
+ const footerConfig = {
112
+ brand: {
113
+ logo: 'https://example.com/logo.png',
114
+ name: 'My Company',
115
+ url: '/'
116
+ },
117
+ navigation: [
118
+ {
119
+ title: 'Product',
120
+ items: [
121
+ { label: 'Features', url: '/features' },
122
+ { label: 'Pricing', url: '/pricing' }
123
+ ]
124
+ }
125
+ ],
126
+ copyright: '© {year} My Company. All rights reserved.'
127
+ }
128
+ </script>
129
+
130
+ <template>
131
+ <div>
132
+ <!-- Your page content -->
133
+
134
+ <!-- Footer at the bottom -->
135
+ <TvFooter :config="footerConfig" />
136
+ </div>
137
+ </template>
138
+ ```
139
+ **Note:** Don't forget to import the CSS in your main entry file as shown above.
140
+
141
+ ## Nuxt 4 / SSR Usage
142
+ First, add the module to your `nuxt.config.ts`:
143
+ ```ts
144
+ // nuxt.config.ts
145
+ export default defineNuxtConfig({
146
+ modules: ['@todovue/tv-footer/nuxt']
147
+ })
148
+ ```
149
+
150
+ Alternatively, you can manually add the CSS:
151
+ ```ts
152
+ // nuxt.config.ts
153
+ export default defineNuxtConfig({
154
+ css: ['@todovue/tv-footer/style.css'],
155
+ })
156
+ ```
157
+
158
+ Then create a plugin file: `plugins/tv-footer.client.ts`:
159
+ ```ts
160
+ import { defineNuxtPlugin } from '#app'
161
+ import TvFooter from '@todovue/tv-footer'
162
+
163
+ export default defineNuxtPlugin(nuxtApp => {
164
+ nuxtApp.vueApp.use(TvFooter)
165
+ })
166
+ ```
167
+ Use anywhere in your Nuxt app:
168
+ ```vue
169
+ <template>
170
+ <div>
171
+ <NuxtPage />
172
+
173
+ <!-- Footer -->
174
+ <TvFooter :config="footerConfig" />
175
+ </div>
176
+ </template>
177
+
178
+ <script setup>
179
+ const footerConfig = {
180
+ brand: {
181
+ logo: 'https://example.com/logo.png',
182
+ url: '/'
183
+ },
184
+ navigation: [
185
+ {
186
+ title: 'Product',
187
+ items: [
188
+ { label: 'Features', url: '/features' }
189
+ ]
190
+ }
191
+ ],
192
+ copyright: '© {year} My Company. All rights reserved.'
193
+ }
194
+ </script>
195
+ ```
196
+ Optional direct import (no plugin):
197
+ ```vue
198
+ <script setup>
199
+ import { TvFooter } from '@todovue/tv-footer'
200
+ </script>
201
+ ```
202
+
203
+ ## Component Registration Options
204
+ | Approach | When to use |
205
+ |--------------------------------------------------------------------------|------------------------------------------------|
206
+ | Global via `app.use(TvFooter)` | Many usages across app / design system install |
207
+ | Local named import `{ TvFooter }` | Isolated / code-split contexts |
208
+ | Direct default import `import TvFooter from '@todovue/tv-footer'` | Single usage or manual registration |
209
+
210
+ ## Props
211
+ | Prop | Type | Default | Description |
212
+ |--------|--------|---------|----------------------------------------------------------------|
213
+ | config | Object | `{}` | Configuration object containing all footer data and settings. |
214
+
215
+ ### Prop Details
216
+
217
+ #### `config`
218
+ The main configuration object that defines all footer content including brand, navigation, social links, legal links, and copyright information. See [Configuration Object](#configuration-object) for detailed structure.
219
+
220
+ Example:
221
+ ```vue
222
+ <TvFooter :config="myFooterConfig" />
223
+ ```
224
+
225
+ ## Events
226
+
227
+ | Event Name | Payload | Description |
228
+ |:------------|:--------|:--------------------------------------------------------------------------------|
229
+ | `subscribe` | `email` | Emitted when the user submits the newsletter form. Payload is the email string. |
230
+
231
+ ## Slots
232
+ TvFooter provides slots to allow custom content injection for specific sections.
233
+
234
+ | Slot Name | Props (Scope) | Description |
235
+ |:-------------|:-------------------------------|:-------------------------------------------------|
236
+ | `brand` | `{ brand, version }` | Replace the brand/logo section |
237
+ | `newsletter` | `{ newsletter }` | Replace the newsletter subscription section |
238
+ | `bottom` | `{ copyright, legal }` | Replace the bottom section (copyright + legal) |
239
+
240
+ Example Usage:
241
+ ```vue
242
+ <TvFooter :config="config">
243
+ <template #brand="{ brand }">
244
+ <div class="custom-brand">
245
+ <h1>{{ brand.name }}</h1>
246
+ </div>
247
+ </template>
248
+ </TvFooter>
249
+ ```
250
+
251
+ ## Configuration Object
252
+ The `config` prop accepts an object with the following structure:
253
+
254
+ ### Brand Section
255
+ ```ts
256
+ {
257
+ brand: {
258
+ logo: string, // URL to logo image (optional)
259
+ name: string, // Brand name (optional, shown if no logo or alongside logo)
260
+ url: string // URL for brand link (default: '/')
261
+ }
262
+ }
263
+ ```
264
+
265
+ ### Version Display
266
+ ```ts
267
+ {
268
+ version: string // Version string to display (e.g., 'v2.4.0')
269
+ }
270
+ ```
271
+
272
+ ### Navigation Sections
273
+ ```ts
274
+ {
275
+ navigation: [
276
+ {
277
+ title: string, // Section title
278
+ items: [
279
+ {
280
+ label: string, // Link text
281
+ url: string // Link URL
282
+ }
283
+ ]
284
+ }
285
+ ]
286
+ }
287
+ ```
288
+
289
+ ### Social Links
290
+ ```ts
291
+ {
292
+ social: [
293
+ {
294
+ label: string, // Accessible label for the link
295
+ url: string, // Social media URL
296
+ iconUrl: string, // URL to icon image (optional)
297
+ icon: string // CSS class for icon (e.g., 'fab fa-github') (optional)
298
+ }
299
+ ]
300
+ }
301
+ ```
302
+
303
+ ### Legal Links
304
+ ```ts
305
+ {
306
+ legal: [
307
+ {
308
+ label: string, // Link text (e.g., 'Privacy Policy')
309
+ url: string // Link URL
310
+ }
311
+ ]
312
+ }
313
+ ```
314
+
315
+ ### Copyright
316
+ ```ts
317
+ {
318
+ copyright: string // Copyright text. Use {year} for automatic year replacement
319
+ }
320
+ ```
321
+
322
+ ### Newsletter Section
323
+ ```ts
324
+ {
325
+ newsletter: {
326
+ title: string, // Newsletter Title (optional)
327
+ description: string, // Newsletter Description (optional)
328
+ placeholder: string, // Input placeholder (optional)
329
+ buttonText: string // Button text (optional)
330
+ }
331
+ }
332
+ ```
333
+
334
+ ### Back To Top
335
+ ```ts
336
+ {
337
+ backToTop: boolean // Show back to top button (default: false)
338
+ }
339
+ ```
340
+
341
+ ### Complete Configuration Example
342
+ ```js
343
+ const footerConfig = {
344
+ brand: {
345
+ logo: 'https://example.com/logo.png',
346
+ name: 'MyApp',
347
+ url: '/'
348
+ },
349
+ version: 'v2.4.0',
350
+ navigation: [
351
+ {
352
+ title: 'Product',
353
+ items: [
354
+ { label: 'Features', url: '/features' },
355
+ { label: 'Pricing', url: '/pricing' },
356
+ { label: 'Showcase', url: '/showcase' }
357
+ ]
358
+ },
359
+ {
360
+ title: 'Resources',
361
+ items: [
362
+ { label: 'Documentation', url: '/docs' },
363
+ { label: 'API Reference', url: '/api' },
364
+ { label: 'Community', url: '/community' }
365
+ ]
366
+ },
367
+ {
368
+ title: 'Company',
369
+ items: [
370
+ { label: 'About Us', url: '/about' },
371
+ { label: 'Blog', url: '/blog' },
372
+ { label: 'Careers', url: '/careers' }
373
+ ]
374
+ }
375
+ ],
376
+ social: [
377
+ {
378
+ label: 'GitHub',
379
+ url: 'https://github.com/mycompany',
380
+ iconUrl: '/icons/github.svg'
381
+ },
382
+ {
383
+ label: 'Twitter',
384
+ url: 'https://twitter.com/mycompany',
385
+ icon: 'fab fa-twitter'
386
+ }
387
+ ],
388
+ legal: [
389
+ { label: 'Privacy Policy', url: '/privacy' },
390
+ { label: 'Terms of Service', url: '/terms' },
391
+ { label: 'Cookie Policy', url: '/cookies' }
392
+ ],
393
+ copyright: '© {year} MyApp. All rights reserved.'
394
+ }
395
+ ```
396
+
397
+ ## Composable API
398
+ TvFooter includes a composable `useFooter` that you can use to process footer configuration and build custom footer implementations.
399
+
400
+ ### `useFooter(config)`
401
+ ```js
402
+ import { useFooter } from '@todovue/tv-footer'
403
+
404
+ const { brand, navigation, social, legal, version, copyright } = useFooter(config)
405
+ ```
406
+
407
+ **Parameters:**
408
+ - `config` (Object): Footer configuration object
409
+
410
+ **Returns:**
411
+ - `brand` (ComputedRef): Processed brand configuration
412
+ - `navigation` (ComputedRef): Array of navigation sections
413
+ - `social` (ComputedRef): Array of social links
414
+ - `legal` (ComputedRef): Array of legal links
415
+ - `version` (ComputedRef): Version string
416
+ - `copyright` (ComputedRef): Copyright text with {year} replaced by current year
417
+
418
+ **Example:**
419
+ ```vue
420
+ <script setup>
421
+ import { useFooter } from '@todovue/tv-footer'
422
+
423
+ const config = {
424
+ brand: { name: 'MyApp', url: '/' },
425
+ copyright: '© {year} MyApp. All rights reserved.'
426
+ }
427
+
428
+ const { brand, copyright } = useFooter(config)
429
+ </script>
430
+
431
+ <template>
432
+ <footer>
433
+ <div>
434
+ <a :href="brand.url">{{ brand.name }}</a>
435
+ </div>
436
+ <div>{{ copyright }}</div>
437
+ </footer>
438
+ </template>
439
+ ```
440
+
441
+ **Features:**
442
+ - Automatic current year replacement in copyright text
443
+ - Safe defaults for missing configuration
444
+ - Reactive computed properties
445
+ - Type-safe array validation
446
+
447
+ ## Usage Examples
448
+
449
+ ### Minimal Footer
450
+ ```vue
451
+ <script setup>
452
+ import { TvFooter } from '@todovue/tv-footer'
453
+ import '@todovue/tv-footer/style.css'
454
+
455
+ const config = {
456
+ copyright: '© {year} My Company. All rights reserved.'
457
+ }
458
+ </script>
459
+
460
+ <template>
461
+ <TvFooter :config="config" />
462
+ </template>
463
+ ```
464
+
465
+ ### Footer with Brand and Navigation
466
+ ```vue
467
+ <script setup>
468
+ import { TvFooter } from '@todovue/tv-footer'
469
+ import '@todovue/tv-footer/style.css'
470
+
471
+ const config = {
472
+ brand: {
473
+ logo: 'https://example.com/logo.png',
474
+ name: 'MyApp',
475
+ url: '/'
476
+ },
477
+ version: 'v1.0.0',
478
+ navigation: [
479
+ {
480
+ title: 'Product',
481
+ items: [
482
+ { label: 'Features', url: '/features' },
483
+ { label: 'Pricing', url: '/pricing' }
484
+ ]
485
+ },
486
+ {
487
+ title: 'Support',
488
+ items: [
489
+ { label: 'Help Center', url: '/help' },
490
+ { label: 'Contact', url: '/contact' }
491
+ ]
492
+ }
493
+ ],
494
+ copyright: '© {year} MyApp. All rights reserved.'
495
+ }
496
+ </script>
497
+
498
+ <template>
499
+ <TvFooter :config="config" />
500
+ </template>
501
+ ```
502
+
503
+ ### Complete Footer with Social & Legal Links
504
+ ```vue
505
+ <script setup>
506
+ import { TvFooter } from '@todovue/tv-footer'
507
+ import '@todovue/tv-footer/style.css'
508
+ import GitHubIcon from './assets/github.svg'
509
+ import TwitterIcon from './assets/twitter.svg'
510
+
511
+ const config = {
512
+ brand: {
513
+ logo: 'https://example.com/logo.png',
514
+ name: 'MyApp',
515
+ url: '/'
516
+ },
517
+ version: 'v2.4.0',
518
+ navigation: [
519
+ {
520
+ title: 'Product',
521
+ items: [
522
+ { label: 'Features', url: '/features' },
523
+ { label: 'Pricing', url: '/pricing' },
524
+ { label: 'Showcase', url: '/showcase' }
525
+ ]
526
+ },
527
+ {
528
+ title: 'Resources',
529
+ items: [
530
+ { label: 'Documentation', url: '/docs' },
531
+ { label: 'API Reference', url: '/api' },
532
+ { label: 'Community', url: '/community' }
533
+ ]
534
+ },
535
+ {
536
+ title: 'Company',
537
+ items: [
538
+ { label: 'About Us', url: '/about' },
539
+ { label: 'Blog', url: '/blog' },
540
+ { label: 'Careers', url: '/careers' }
541
+ ]
542
+ }
543
+ ],
544
+ social: [
545
+ {
546
+ label: 'GitHub',
547
+ url: 'https://github.com/mycompany',
548
+ iconUrl: GitHubIcon
549
+ },
550
+ {
551
+ label: 'Twitter',
552
+ url: 'https://twitter.com/mycompany',
553
+ iconUrl: TwitterIcon
554
+ }
555
+ ],
556
+ legal: [
557
+ { label: 'Privacy Policy', url: '/privacy' },
558
+ { label: 'Terms of Service', url: '/terms' },
559
+ { label: 'Cookie Policy', url: '/cookies' }
560
+ ],
561
+ copyright: '© {year} MyApp. All rights reserved.'
562
+ }
563
+ </script>
564
+
565
+ <template>
566
+ <div>
567
+ <!-- Your page content -->
568
+ <main>
569
+ <!-- ... -->
570
+ </main>
571
+
572
+ <!-- Footer -->
573
+ <TvFooter :config="config" />
574
+ </div>
575
+ </template>
576
+ ```
577
+
578
+ ### Using Icon Libraries (Font Awesome, etc.)
579
+ ```vue
580
+ <script setup>
581
+ import { TvFooter } from '@todovue/tv-footer'
582
+ import '@todovue/tv-footer/style.css'
583
+
584
+ const config = {
585
+ social: [
586
+ {
587
+ label: 'GitHub',
588
+ url: 'https://github.com/mycompany',
589
+ icon: 'fab fa-github' // Font Awesome class
590
+ },
591
+ {
592
+ label: 'Twitter',
593
+ url: 'https://twitter.com/mycompany',
594
+ icon: 'fab fa-twitter' // Font Awesome class
595
+ },
596
+ {
597
+ label: 'LinkedIn',
598
+ url: 'https://linkedin.com/company/mycompany',
599
+ icon: 'fab fa-linkedin' // Font Awesome class
600
+ }
601
+ ],
602
+ copyright: '© {year} MyApp. All rights reserved.'
603
+ }
604
+ </script>
605
+
606
+ <template>
607
+ <TvFooter :config="config" />
608
+ </template>
609
+ ```
610
+
611
+ ### Custom Implementation with Composable
612
+ ```vue
613
+ <script setup>
614
+ import { useFooter } from '@todovue/tv-footer'
615
+
616
+ const config = {
617
+ brand: {
618
+ name: 'MyApp',
619
+ url: '/'
620
+ },
621
+ navigation: [
622
+ {
623
+ title: 'Links',
624
+ items: [
625
+ { label: 'Home', url: '/' },
626
+ { label: 'About', url: '/about' }
627
+ ]
628
+ }
629
+ ],
630
+ copyright: '© {year} MyApp. All rights reserved.'
631
+ }
632
+
633
+ const { brand, navigation, copyright } = useFooter(config)
634
+ </script>
635
+
636
+ <template>
637
+ <footer class="custom-footer">
638
+ <div class="custom-footer__brand">
639
+ <a :href="brand.url">{{ brand.name }}</a>
640
+ </div>
641
+
642
+ <nav v-for="(section, index) in navigation" :key="index">
643
+ <h4>{{ section.title }}</h4>
644
+ <ul>
645
+ <li v-for="(link, i) in section.items" :key="i">
646
+ <a :href="link.url">{{ link.label }}</a>
647
+ </li>
648
+ </ul>
649
+ </nav>
650
+
651
+ <div class="custom-footer__copyright">
652
+ {{ copyright }}
653
+ </div>
654
+ </footer>
655
+ </template>
656
+
657
+ <style scoped>
658
+ .custom-footer {
659
+ /* Your custom styles */
660
+ }
661
+ </style>
662
+ ```
663
+
664
+ ## Styling
665
+ TvFooter comes with built-in responsive styles and light/dark mode support.
666
+
667
+ ### Built-in Features
668
+ - **Responsive Grid Layout**:
669
+ - Mobile (< 640px): 1 column
670
+ - Tablet (≥ 640px): 2 columns
671
+ - Desktop (≥ 1024px): 4 columns
672
+ - **Dark Mode Support**: Automatically adapts to `.dark-mode` class on parent
673
+ - **Light Mode Support**: Adapts to `.light-mode` class on parent
674
+ - **Hover Effects**: Smooth transitions on links and social icons
675
+ - **Backdrop Blur**: Modern glassmorphism effect on social icons
676
+
677
+ ### Customization
678
+ You can override the default styles by targeting the CSS classes:
679
+
680
+ ```css
681
+ /* Override brand logo size */
682
+ .tv-footer__logo img {
683
+ height: 80px;
684
+ }
685
+
686
+ /* Change link colors */
687
+ .tv-footer__link {
688
+ color: #your-color;
689
+ }
690
+
691
+ .tv-footer__link:hover {
692
+ color: #your-hover-color;
693
+ }
694
+
695
+ /* Customize social icons */
696
+ .tv-footer__social-link {
697
+ background-color: #your-background;
698
+ }
699
+
700
+ /* Adjust spacing */
701
+ .tv-footer {
702
+ padding: 3rem 1rem;
703
+ }
704
+
705
+ /* Customize container max-width */
706
+ .tv-footer__container {
707
+ max-width: 1400px;
708
+ }
709
+ ```
710
+
711
+ ### Available CSS Classes
712
+ - `.tv-footer` - Main footer container
713
+ - `.tv-footer__container` - Inner grid container
714
+ - `.tv-footer__brand` - Brand section
715
+ - `.tv-footer__logo` - Brand logo/name link
716
+ - `.tv-footer__version` - Version display
717
+ - `.tv-footer__section` - Navigation or social section
718
+ - `.tv-footer__section-title` - Section title
719
+ - `.tv-footer__links` - List of links
720
+ - `.tv-footer__link` - Individual link
721
+ - `.tv-footer__social` - Social links container
722
+ - `.tv-footer__social-link` - Individual social link
723
+ - `.tv-footer__social-icon-img` - Social icon image
724
+ - `.tv-footer__bottom` - Bottom section with copyright and legal
725
+ - `.tv-footer__legal` - Legal links container
726
+
727
+ ## Accessibility
728
+ - **Semantic HTML**: Uses proper `<footer>`, `<nav>`, `<ul>`, and `<a>` elements
729
+ - **ARIA Labels**: Social links include accessible labels
730
+ - **External Link Safety**: Social links include `rel="noopener noreferrer"` for security
731
+ - **Keyboard Navigation**: All links are keyboard accessible
732
+ - **Focus States**: Clear focus indicators for keyboard navigation
733
+ - **Screen Reader Friendly**: Proper heading hierarchy and semantic structure
734
+ - **Alternative Text**: Images include alt attributes
735
+
736
+ ## SSR Notes
737
+ - **SSR-Safe**: No direct `window`/`document` access during module evaluation
738
+ - **Nuxt 3 Compatible**: Works seamlessly with Nuxt 3 out of the box
739
+ - **Hydration Safe**: No hydration mismatches
740
+ - **Universal Rendering**: Works in both client and server contexts
741
+ - **Vue 3 Composition API**: Uses modern Vue 3 composables
742
+
743
+ ## Development
744
+ ```bash
745
+ git clone https://github.com/TODOvue/tv-footer.git
746
+ cd tv-footer
747
+ npm install
748
+ npm run dev # run demo playground
749
+ npm run build # build library
750
+ ```
751
+ Local demo served from Vite using `index.html` and demo examples in `src/demo`.
752
+
753
+ ## Contributing
754
+ PRs and issues welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
755
+
756
+ ## License
757
+ MIT © TODOvue
758
+
759
+ ### Attributions
760
+ Crafted for the TODOvue component ecosystem