mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-12 19:04:45 +08:00
244 lines
5.7 KiB
Markdown
244 lines
5.7 KiB
Markdown
|
|
# Common Components
|
||
|
|
|
||
|
|
This directory contains reusable Vue 3 components built with Composition API, TypeScript, and TailwindCSS.
|
||
|
|
|
||
|
|
## Components
|
||
|
|
|
||
|
|
### DataTable.vue
|
||
|
|
A generic data table component with sorting, loading states, and custom cell rendering.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `columns: Column[]` - Array of column definitions with key, label, sortable, and formatter
|
||
|
|
- `data: any[]` - Array of data objects to display
|
||
|
|
- `loading?: boolean` - Show loading skeleton
|
||
|
|
|
||
|
|
**Slots:**
|
||
|
|
- `empty` - Custom empty state content
|
||
|
|
- `cell-{key}` - Custom cell renderer for specific column (receives `row` and `value`)
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<DataTable
|
||
|
|
:columns="[
|
||
|
|
{ key: 'name', label: 'Name', sortable: true },
|
||
|
|
{ key: 'email', label: 'Email' },
|
||
|
|
{ key: 'status', label: 'Status', formatter: (val) => val.toUpperCase() }
|
||
|
|
]"
|
||
|
|
:data="users"
|
||
|
|
:loading="isLoading"
|
||
|
|
>
|
||
|
|
<template #cell-actions="{ row }">
|
||
|
|
<button @click="editUser(row)">Edit</button>
|
||
|
|
</template>
|
||
|
|
</DataTable>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Pagination.vue
|
||
|
|
Pagination component with page numbers, navigation, and page size selector.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `total: number` - Total number of items
|
||
|
|
- `page: number` - Current page (1-indexed)
|
||
|
|
- `pageSize: number` - Items per page
|
||
|
|
- `pageSizeOptions?: number[]` - Available page size options (default: [10, 20, 50, 100])
|
||
|
|
|
||
|
|
**Events:**
|
||
|
|
- `update:page` - Emitted when page changes
|
||
|
|
- `update:pageSize` - Emitted when page size changes
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<Pagination
|
||
|
|
:total="totalUsers"
|
||
|
|
:page="currentPage"
|
||
|
|
:pageSize="pageSize"
|
||
|
|
@update:page="currentPage = $event"
|
||
|
|
@update:pageSize="pageSize = $event"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Modal.vue
|
||
|
|
Modal dialog with customizable size and close behavior.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `show: boolean` - Control modal visibility
|
||
|
|
- `title: string` - Modal title
|
||
|
|
- `size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'` - Modal size (default: 'md')
|
||
|
|
- `closeOnEscape?: boolean` - Close on Escape key (default: true)
|
||
|
|
- `closeOnClickOutside?: boolean` - Close on backdrop click (default: true)
|
||
|
|
|
||
|
|
**Events:**
|
||
|
|
- `close` - Emitted when modal should close
|
||
|
|
|
||
|
|
**Slots:**
|
||
|
|
- `default` - Modal body content
|
||
|
|
- `footer` - Modal footer content
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<Modal :show="showModal" title="Edit User" size="lg" @close="showModal = false">
|
||
|
|
<form @submit.prevent="saveUser">
|
||
|
|
<!-- Form content -->
|
||
|
|
</form>
|
||
|
|
|
||
|
|
<template #footer>
|
||
|
|
<button @click="showModal = false">Cancel</button>
|
||
|
|
<button @click="saveUser">Save</button>
|
||
|
|
</template>
|
||
|
|
</Modal>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### ConfirmDialog.vue
|
||
|
|
Confirmation dialog built on top of Modal component.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `show: boolean` - Control dialog visibility
|
||
|
|
- `title: string` - Dialog title
|
||
|
|
- `message: string` - Confirmation message
|
||
|
|
- `confirmText?: string` - Confirm button text (default: 'Confirm')
|
||
|
|
- `cancelText?: string` - Cancel button text (default: 'Cancel')
|
||
|
|
- `danger?: boolean` - Use danger/red styling (default: false)
|
||
|
|
|
||
|
|
**Events:**
|
||
|
|
- `confirm` - Emitted when user confirms
|
||
|
|
- `cancel` - Emitted when user cancels
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<ConfirmDialog
|
||
|
|
:show="showDeleteConfirm"
|
||
|
|
title="Delete User"
|
||
|
|
message="Are you sure you want to delete this user? This action cannot be undone."
|
||
|
|
confirm-text="Delete"
|
||
|
|
cancel-text="Cancel"
|
||
|
|
danger
|
||
|
|
@confirm="deleteUser"
|
||
|
|
@cancel="showDeleteConfirm = false"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### StatCard.vue
|
||
|
|
Statistics card component for displaying metrics with optional change indicators.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `title: string` - Card title
|
||
|
|
- `value: number | string` - Main value to display
|
||
|
|
- `icon?: Component` - Icon component
|
||
|
|
- `change?: number` - Percentage change value
|
||
|
|
- `changeType?: 'up' | 'down' | 'neutral'` - Change direction (default: 'neutral')
|
||
|
|
- `formatValue?: (value) => string` - Custom value formatter
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<StatCard
|
||
|
|
title="Total Users"
|
||
|
|
:value="1234"
|
||
|
|
:icon="UserIcon"
|
||
|
|
:change="12.5"
|
||
|
|
change-type="up"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Toast.vue
|
||
|
|
Toast notification component that automatically displays toasts from the app store.
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<!-- Add once in App.vue or layout -->
|
||
|
|
<Toast />
|
||
|
|
```
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// Trigger toasts from anywhere using the app store
|
||
|
|
import { useAppStore } from '@/stores/app'
|
||
|
|
|
||
|
|
const appStore = useAppStore()
|
||
|
|
|
||
|
|
appStore.addToast({
|
||
|
|
type: 'success',
|
||
|
|
title: 'Success!',
|
||
|
|
message: 'User created successfully',
|
||
|
|
duration: 3000
|
||
|
|
})
|
||
|
|
|
||
|
|
appStore.addToast({
|
||
|
|
type: 'error',
|
||
|
|
message: 'Failed to delete user'
|
||
|
|
})
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### LoadingSpinner.vue
|
||
|
|
Simple animated loading spinner.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `size?: 'sm' | 'md' | 'lg' | 'xl'` - Spinner size (default: 'md')
|
||
|
|
- `color?: 'primary' | 'secondary' | 'white' | 'gray'` - Spinner color (default: 'primary')
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<LoadingSpinner size="lg" color="primary" />
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### EmptyState.vue
|
||
|
|
Empty state placeholder with icon, message, and optional action button.
|
||
|
|
|
||
|
|
**Props:**
|
||
|
|
- `icon?: Component` - Icon component
|
||
|
|
- `title: string` - Empty state title
|
||
|
|
- `description: string` - Empty state description
|
||
|
|
- `actionText?: string` - Action button text
|
||
|
|
- `actionTo?: string | object` - Router link destination
|
||
|
|
- `actionIcon?: boolean` - Show plus icon in button (default: true)
|
||
|
|
|
||
|
|
**Slots:**
|
||
|
|
- `icon` - Custom icon content
|
||
|
|
- `action` - Custom action button/link
|
||
|
|
|
||
|
|
**Usage:**
|
||
|
|
```vue
|
||
|
|
<EmptyState
|
||
|
|
title="No users found"
|
||
|
|
description="Get started by creating your first user account."
|
||
|
|
action-text="Add User"
|
||
|
|
:action-to="{ name: 'users-create' }"
|
||
|
|
/>
|
||
|
|
```
|
||
|
|
|
||
|
|
## Import
|
||
|
|
|
||
|
|
You can import components individually:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { DataTable, Pagination, Modal } from '@/components/common'
|
||
|
|
```
|
||
|
|
|
||
|
|
Or import specific components:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import DataTable from '@/components/common/DataTable.vue'
|
||
|
|
```
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
All components include:
|
||
|
|
- **TypeScript support** with proper type definitions
|
||
|
|
- **Accessibility** with ARIA attributes and keyboard navigation
|
||
|
|
- **Responsive design** with mobile-friendly layouts
|
||
|
|
- **TailwindCSS styling** for consistent design
|
||
|
|
- **Vue 3 Composition API** with `<script setup>`
|
||
|
|
- **Slot support** for customization
|