@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.
- package/README.md +20 -20
- package/dist/entry.d.ts +2 -2
- package/dist/tv-ui.cjs.js +1 -1
- package/dist/tv-ui.css +1 -1
- package/dist/tv-ui.es.js +50 -49
- package/package.json +4 -2
- package/dist/.htaccess +0 -8
- package/dist/demos/tv-alert/CHANGELOG.md +0 -127
- package/dist/demos/tv-alert/README.md +0 -334
- package/dist/demos/tv-article/CHANGELOG.md +0 -221
- package/dist/demos/tv-article/README.md +0 -258
- package/dist/demos/tv-breadcrumbs/CHANGELOG.md +0 -135
- package/dist/demos/tv-breadcrumbs/README.md +0 -364
- package/dist/demos/tv-button/CHANGELOG.md +0 -158
- package/dist/demos/tv-button/README.md +0 -255
- package/dist/demos/tv-card/CHANGELOG.md +0 -158
- package/dist/demos/tv-card/README.md +0 -332
- package/dist/demos/tv-demo/CHANGELOG.md +0 -352
- package/dist/demos/tv-demo/README.md +0 -229
- package/dist/demos/tv-footer/CHANGELOG.md +0 -67
- package/dist/demos/tv-footer/README.md +0 -760
- package/dist/demos/tv-hero/CHANGELOG.md +0 -137
- package/dist/demos/tv-hero/README.md +0 -410
- package/dist/demos/tv-label/CHANGELOG.md +0 -138
- package/dist/demos/tv-label/README.md +0 -357
- package/dist/demos/tv-menu/CHANGELOG.md +0 -145
- package/dist/demos/tv-menu/README.md +0 -389
- package/dist/demos/tv-modal/CHANGELOG.md +0 -127
- package/dist/demos/tv-modal/README.md +0 -466
- package/dist/demos/tv-pagination/CHANGELOG.md +0 -125
- package/dist/demos/tv-pagination/README.md +0 -275
- package/dist/demos/tv-progress-bar/CHANGELOG.md +0 -84
- package/dist/demos/tv-progress-bar/README.md +0 -894
- package/dist/demos/tv-relative-time/CHANGELOG.md +0 -122
- package/dist/demos/tv-relative-time/README.md +0 -405
- package/dist/demos/tv-scroll-top/CHANGELOG.md +0 -69
- package/dist/demos/tv-scroll-top/README.md +0 -445
- package/dist/demos/tv-search/CHANGELOG.md +0 -155
- package/dist/demos/tv-search/README.md +0 -407
- package/dist/demos/tv-settings/CHANGELOG.md +0 -94
- package/dist/demos/tv-settings/README.md +0 -314
- package/dist/demos/tv-sidebar/CHANGELOG.md +0 -229
- package/dist/demos/tv-sidebar/README.md +0 -592
- package/dist/demos/tv-theme-button/CHANGELOG.md +0 -136
- package/dist/demos/tv-theme-button/README.md +0 -392
- package/dist/demos/tv-toc/CHANGELOG.md +0 -80
- package/dist/demos/tv-toc/README.md +0 -288
- package/dist/favicon.ico +0 -0
|
@@ -1,760 +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 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
|
-
[](https://www.npmjs.com/package/@todovue/tv-footer)
|
|
8
|
-
[](https://www.npmjs.com/package/@todovue/tv-footer)
|
|
9
|
-
[](https://www.npmjs.com/package/@todovue/tv-footer)
|
|
10
|
-

|
|
11
|
-

|
|
12
|
-

|
|
13
|
-

|
|
14
|
-

|
|
15
|
-

|
|
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
|