@kikiloaw/simple-table 1.0.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.
- package/LICENSE +21 -0
- package/README.md +731 -0
- package/package.json +32 -0
- package/src/SimpleTable.vue +795 -0
- package/src/components/table/Table.vue +25 -0
- package/src/components/table/TableBody.vue +23 -0
- package/src/components/table/TableCell.vue +23 -0
- package/src/components/table/TableHead.vue +28 -0
- package/src/components/table/TableHeader.vue +20 -0
- package/src/components/table/TableRow.vue +28 -0
- package/src/components/table/index.ts +6 -0
- package/src/index.d.ts +6 -0
- package/src/index.js +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
# ð SimpleTable
|
|
2
|
+
|
|
3
|
+
> A lightweight, dependency-light DataTable component for Vue 3 with Tailwind CSS. Built for simplicity, performance, and maximum compatibility.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://vuejs.org/)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## âĻ Why SimpleTable?
|
|
12
|
+
|
|
13
|
+
- **ðŠķ Lightweight**: Uses native HTML elements (`<select>`, `<input>`, `<button>`)
|
|
14
|
+
- **ðĻ Beautiful**: Premium Tailwind CSS styling out of the box
|
|
15
|
+
- **⥠Fast**: Client-side response caching to minimize API calls
|
|
16
|
+
- **ð Flexible**: Works with Laravel, DataTables, or any REST API
|
|
17
|
+
- **ðą Responsive**: Mobile-first design with smart pagination
|
|
18
|
+
- **ðŊ Type-Safe**: Full TypeScript support with autocomplete
|
|
19
|
+
- **ð Zero Dependencies**: No Radix, no Headless UI, just Vue + Tailwind
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## ðĶ Installation
|
|
24
|
+
|
|
25
|
+
### Option 1: NPM Package
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @kikiloaw/simple-table
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Option 2: Local Copy
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cp -r path/to/SimpleTable /your-project/src/components/
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ð Quick Start
|
|
40
|
+
|
|
41
|
+
### 1. Import the Component
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<script setup>
|
|
45
|
+
import { ref } from 'vue'
|
|
46
|
+
import SimpleTable from '@kikiloaw/simple-table'
|
|
47
|
+
|
|
48
|
+
const columns = [
|
|
49
|
+
{ key: 'id', label: 'ID', sortable: true, width: '80px' },
|
|
50
|
+
{ key: 'name', label: 'Name', sortable: true },
|
|
51
|
+
{ key: 'email', label: 'Email' },
|
|
52
|
+
{ key: 'status', label: 'Status', width: '120px' }
|
|
53
|
+
]
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<SimpleTable
|
|
58
|
+
fetch-url="/api/users"
|
|
59
|
+
:columns="columns"
|
|
60
|
+
searchable
|
|
61
|
+
/>
|
|
62
|
+
</template>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 2. Backend Setup (Laravel)
|
|
66
|
+
|
|
67
|
+
```php
|
|
68
|
+
public function getData(Request $request)
|
|
69
|
+
{
|
|
70
|
+
$query = User::query();
|
|
71
|
+
|
|
72
|
+
// Handle search
|
|
73
|
+
if ($search = $request->input('search')) {
|
|
74
|
+
$query->where('name', 'like', "%{$search}%");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Handle sorting
|
|
78
|
+
if ($sort = $request->input('sort')) {
|
|
79
|
+
$query->orderBy($sort, $request->input('order', 'asc'));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return response()->json($query->paginate($request->input('per_page', 10)));
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**That's it!** You now have a fully functional data table! ð
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ð Table of Contents
|
|
91
|
+
|
|
92
|
+
- [Core Concepts](#-core-concepts)
|
|
93
|
+
- [Props Reference](#-props-reference)
|
|
94
|
+
- [Column Configuration](#-column-configuration)
|
|
95
|
+
- [Features](#-features)
|
|
96
|
+
- [Custom Sort Keys](#custom-sort-keys)
|
|
97
|
+
- [Advanced Filtering](#advanced-filtering-query-parameters)
|
|
98
|
+
- [Response Caching](#response-caching)
|
|
99
|
+
- [Custom Actions](#custom-actions-and-slots)
|
|
100
|
+
- [Cell Customization](#custom-cell-rendering)
|
|
101
|
+
- [DataTables Compatibility](#-datatables-compatibility)
|
|
102
|
+
- [Backend Integration](#-backend-integration)
|
|
103
|
+
- [Styling](#-styling-customization)
|
|
104
|
+
- [Troubleshooting](#-troubleshooting)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## ðŊ Core Concepts
|
|
109
|
+
|
|
110
|
+
### Data Modes
|
|
111
|
+
|
|
112
|
+
SimpleTable supports three data modes:
|
|
113
|
+
|
|
114
|
+
| Mode | When to Use | Example |
|
|
115
|
+
|------|-------------|---------|
|
|
116
|
+
| **`auto`** (default) | Auto-detect based on data structure | Recommended for most cases |
|
|
117
|
+
| **`server`** | Force server-side pagination | Large datasets (10,000+ rows) |
|
|
118
|
+
| **`client`** | Force client-side pagination | Small static datasets (<1,000 rows) |
|
|
119
|
+
|
|
120
|
+
### Protocol Formats
|
|
121
|
+
|
|
122
|
+
| Protocol | When to Use | Backend Library |
|
|
123
|
+
|----------|-------------|-----------------|
|
|
124
|
+
| **`laravel`** (default) | New projects, standard Laravel apps | Native Laravel pagination |
|
|
125
|
+
| **`datatables`** | Legacy projects, existing DataTables | Yajra DataTables |
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## ð Props Reference
|
|
130
|
+
|
|
131
|
+
### Essential Props
|
|
132
|
+
|
|
133
|
+
| Prop | Type | Default | Description |
|
|
134
|
+
|------|------|---------|-------------|
|
|
135
|
+
| `columns` | Array | **Required** | Column definitions ([see below](#-column-configuration)) |
|
|
136
|
+
| `fetchUrl` | String | `null` | API endpoint for server-side data |
|
|
137
|
+
| `data` | Array/Object | `[]` | Static data or Laravel Paginator object |
|
|
138
|
+
|
|
139
|
+
### Behavior Props
|
|
140
|
+
|
|
141
|
+
| Prop | Type | Default | Description |
|
|
142
|
+
|------|------|---------|-------------|
|
|
143
|
+
| `mode` | String | `'auto'` | Data mode: `'auto'`, `'server'`, or `'client'` |
|
|
144
|
+
| `protocol` | String | `'laravel'` | API format: `'laravel'` or `'datatables'` |
|
|
145
|
+
| `searchable` | Boolean | `true` | Enable search input |
|
|
146
|
+
| `enableCache` | Boolean | `false` | Cache API responses |
|
|
147
|
+
|
|
148
|
+
### Pagination Props
|
|
149
|
+
|
|
150
|
+
| Prop | Type | Default | Description |
|
|
151
|
+
|------|------|---------|-------------|
|
|
152
|
+
| `perPage` | Number | `10` | Default rows per page |
|
|
153
|
+
| `pageSizes` | Array | `[10,20,30,50,100]` | Page size dropdown options |
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
### Advanced Props
|
|
157
|
+
|
|
158
|
+
| Prop | Type | Default | Description |
|
|
159
|
+
|------|------|---------|-------------|
|
|
160
|
+
| `queryParams` | Object | `{}` | Additional parameters for every request |
|
|
161
|
+
| `oddRowColor` | String | `'bg-background'` | Tailwind class for odd rows |
|
|
162
|
+
| `evenRowColor` | String | `'bg-background'` | Tailwind class for even rows |
|
|
163
|
+
| `hoverColor` | String | `'hover:bg-muted/50'` | Tailwind class for row hover |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## ðïļ Column Configuration
|
|
168
|
+
|
|
169
|
+
### Basic Column
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
{
|
|
173
|
+
key: 'name', // Required: Property key from data
|
|
174
|
+
label: 'Name', // Required: Column header text
|
|
175
|
+
sortable: true, // Optional: Enable sorting
|
|
176
|
+
width: '200px', // Optional: Fixed column width
|
|
177
|
+
fixed: true, // Optional: Sticky column (useful for actions)
|
|
178
|
+
class: 'text-center' // Optional: Additional CSS classes
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Sortable Options
|
|
183
|
+
|
|
184
|
+
| Value | Behavior | Example |
|
|
185
|
+
|-------|----------|---------|
|
|
186
|
+
| `false` | Not sortable | `sortable: false` (default) |
|
|
187
|
+
| `true` | Sortable using `key` | `{ key: 'name', sortable: true }` |
|
|
188
|
+
| `'column_name'` | Sort by custom column | `{ key: 'user.name', sortable: 'user_id' }` |
|
|
189
|
+
|
|
190
|
+
### Complete Example
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const columns = [
|
|
194
|
+
// Simple sortable column
|
|
195
|
+
{
|
|
196
|
+
key: 'id',
|
|
197
|
+
label: 'ID',
|
|
198
|
+
sortable: true,
|
|
199
|
+
width: '80px'
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// Custom sort key (for relationships)
|
|
203
|
+
{
|
|
204
|
+
key: 'department.name', // Display: department name
|
|
205
|
+
label: 'Department',
|
|
206
|
+
sortable: 'department_id' // Sort by: department_id
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// Non-sortable column
|
|
210
|
+
{
|
|
211
|
+
key: 'email',
|
|
212
|
+
label: 'Email'
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
// Sticky actions column (always visible)
|
|
216
|
+
{
|
|
217
|
+
key: 'actions',
|
|
218
|
+
label: 'Actions',
|
|
219
|
+
fixed: true,
|
|
220
|
+
width: '120px'
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### ðĄ **When to Use Custom Sort Keys**
|
|
226
|
+
|
|
227
|
+
Use custom sort keys when:
|
|
228
|
+
- Displaying relationship data (e.g., `user.department.name`)
|
|
229
|
+
- Sorting by foreign keys instead of displayed values
|
|
230
|
+
- Your database column name differs from the display key
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## ðĻ Features
|
|
235
|
+
|
|
236
|
+
### Custom Sort Keys
|
|
237
|
+
|
|
238
|
+
**Problem:** You want to display `department.name` but sort by `department_id`.
|
|
239
|
+
|
|
240
|
+
**Solution:**
|
|
241
|
+
|
|
242
|
+
```vue
|
|
243
|
+
<script setup>
|
|
244
|
+
const columns = [
|
|
245
|
+
{
|
|
246
|
+
key: 'department.name', // What users see
|
|
247
|
+
label: 'Department',
|
|
248
|
+
sortable: 'department_id' // What backend sorts by
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<template>
|
|
254
|
+
<SimpleTable :columns="columns" fetch-url="/api/users" />
|
|
255
|
+
</template>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Backend receives:** `?sort=department_id&order=asc`
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### Advanced Filtering (Query Parameters)
|
|
263
|
+
|
|
264
|
+
**Use Case:** Add filters like status, department, date range, etc.
|
|
265
|
+
|
|
266
|
+
```vue
|
|
267
|
+
<script setup>
|
|
268
|
+
import { ref } from 'vue'
|
|
269
|
+
|
|
270
|
+
const filters = ref({
|
|
271
|
+
status: 'active',
|
|
272
|
+
department_id: 5,
|
|
273
|
+
year: 2025
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
function updateStatus(newStatus) {
|
|
277
|
+
filters.value.status = newStatus
|
|
278
|
+
// Table automatically refetches!
|
|
279
|
+
}
|
|
280
|
+
</script>
|
|
281
|
+
|
|
282
|
+
<template>
|
|
283
|
+
<!-- Your filter UI -->
|
|
284
|
+
<div class="mb-4 flex gap-4">
|
|
285
|
+
<select v-model="filters.status">
|
|
286
|
+
<option value="active">Active</option>
|
|
287
|
+
<option value="inactive">Inactive</option>
|
|
288
|
+
</select>
|
|
289
|
+
|
|
290
|
+
<select v-model="filters.department_id">
|
|
291
|
+
<option :value="1">IT</option>
|
|
292
|
+
<option :value="5">HR</option>
|
|
293
|
+
</select>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<!-- Table with filters -->
|
|
297
|
+
<SimpleTable
|
|
298
|
+
fetch-url="/api/users"
|
|
299
|
+
:columns="columns"
|
|
300
|
+
:query-params="filters"
|
|
301
|
+
/>
|
|
302
|
+
</template>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**API Request:**
|
|
306
|
+
```
|
|
307
|
+
GET /api/users?page=1&per_page=10&status=active&department_id=5&year=2025
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Backend:**
|
|
311
|
+
```php
|
|
312
|
+
public function getData(Request $request)
|
|
313
|
+
{
|
|
314
|
+
$query = User::query();
|
|
315
|
+
|
|
316
|
+
// Your custom filters
|
|
317
|
+
if ($status = $request->input('status')) {
|
|
318
|
+
$query->where('status', $status);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if ($deptId = $request->input('department_id')) {
|
|
322
|
+
$query->where('department_id', $deptId);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return response()->json($query->paginate($request->per_page));
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### Response Caching
|
|
332
|
+
|
|
333
|
+
**Benefit:** Reduce API calls when users navigate back to previously viewed pages.
|
|
334
|
+
|
|
335
|
+
```vue
|
|
336
|
+
<SimpleTable
|
|
337
|
+
fetch-url="/api/users"
|
|
338
|
+
:columns="columns"
|
|
339
|
+
enable-cache <!-- ð Add this -->
|
|
340
|
+
/>
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**How it works:**
|
|
344
|
+
1. User goes to Page 1 â API call made, response cached
|
|
345
|
+
2. User goes to Page 2 â API call made, response cached
|
|
346
|
+
3. User goes back to Page 1 â **No API call** (uses cache)
|
|
347
|
+
|
|
348
|
+
**Clear cache after data changes:**
|
|
349
|
+
|
|
350
|
+
```vue
|
|
351
|
+
<script setup>
|
|
352
|
+
const tableRef = ref()
|
|
353
|
+
|
|
354
|
+
function handleCreate() {
|
|
355
|
+
// After creating/updating data
|
|
356
|
+
tableRef.value?.clearCache()
|
|
357
|
+
tableRef.value?.refresh()
|
|
358
|
+
}
|
|
359
|
+
</script>
|
|
360
|
+
|
|
361
|
+
<template>
|
|
362
|
+
<SimpleTable ref="tableRef" enable-cache />
|
|
363
|
+
</template>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
#### â
**When to Enable Caching**
|
|
367
|
+
|
|
368
|
+
- â
Reference data (countries, departments, etc.)
|
|
369
|
+
- â
Historical data that doesn't change
|
|
370
|
+
- â
User wants to revisit previous pages
|
|
371
|
+
|
|
372
|
+
#### â **When NOT to Enable Caching**
|
|
373
|
+
|
|
374
|
+
- â Real-time dashboards
|
|
375
|
+
- â Frequently updated data
|
|
376
|
+
- â Collaborative editing interfaces
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
### Custom Actions and Slots
|
|
381
|
+
|
|
382
|
+
**Add custom buttons to the toolbar:**
|
|
383
|
+
|
|
384
|
+
```vue
|
|
385
|
+
<SimpleTable :columns="columns" fetch-url="/api/users">
|
|
386
|
+
<template #actions="{ rows }">
|
|
387
|
+
<button @click="exportCustom(rows)" class="btn">
|
|
388
|
+
Custom Export
|
|
389
|
+
</button>
|
|
390
|
+
<button @click="bulkDelete(rows)" class="btn btn-danger">
|
|
391
|
+
Bulk Delete
|
|
392
|
+
</button>
|
|
393
|
+
</template>
|
|
394
|
+
</SimpleTable>
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Access to:**
|
|
398
|
+
- `rows`: Currently visible data
|
|
399
|
+
- `columns`: Column definitions
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Custom Cell Rendering
|
|
404
|
+
|
|
405
|
+
**Customize how data is displayed in specific columns:**
|
|
406
|
+
|
|
407
|
+
```vue
|
|
408
|
+
<SimpleTable :columns="columns" fetch-url="/api/users">
|
|
409
|
+
<!-- Custom status badge -->
|
|
410
|
+
<template #cell-status="{ row }">
|
|
411
|
+
<span
|
|
412
|
+
:class="row.status === 'active' ? 'badge-success' : 'badge-danger'"
|
|
413
|
+
>
|
|
414
|
+
{{ row.status }}
|
|
415
|
+
</span>
|
|
416
|
+
</template>
|
|
417
|
+
|
|
418
|
+
<!-- Custom actions column -->
|
|
419
|
+
<template #cell-actions="{ row }">
|
|
420
|
+
<button @click="edit(row)" class="btn-sm">Edit</button>
|
|
421
|
+
<button @click="delete(row)" class="btn-sm btn-danger">Delete</button>
|
|
422
|
+
</template>
|
|
423
|
+
</SimpleTable>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Slot Naming:** `#cell-{columnKey}`
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## ð DataTables Compatibility
|
|
431
|
+
|
|
432
|
+
**Migrating from jQuery DataTables?** SimpleTable has full backward compatibility!
|
|
433
|
+
|
|
434
|
+
### Quick Migration
|
|
435
|
+
|
|
436
|
+
**Before (jQuery DataTables):**
|
|
437
|
+
```javascript
|
|
438
|
+
$('#myTable').DataTable({
|
|
439
|
+
serverSide: true,
|
|
440
|
+
ajax: '/api/users'
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**After (SimpleTable):**
|
|
445
|
+
```vue
|
|
446
|
+
<SimpleTable
|
|
447
|
+
fetch-url="/api/users"
|
|
448
|
+
:columns="columns"
|
|
449
|
+
protocol="datatables" <!-- ð This is the magic! -->
|
|
450
|
+
/>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**No backend changes required!** â
|
|
454
|
+
|
|
455
|
+
### Request Format
|
|
456
|
+
|
|
457
|
+
**SimpleTable sends:**
|
|
458
|
+
```
|
|
459
|
+
GET /api/users?start=0&length=10&draw=1&search[value]=john&order[0][column]=1&order[0][dir]=asc
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
| Parameter | Description | Example |
|
|
463
|
+
|-----------|-------------|---------|
|
|
464
|
+
| `start` | Record offset | `0`, `10`, `20` |
|
|
465
|
+
| `length` | Records per page | `10`, `25`, `50` |
|
|
466
|
+
| `draw` | Request counter | `1`, `2`, `3` |
|
|
467
|
+
| `search[value]` | Search query | `john`, `admin` |
|
|
468
|
+
| `order[0][column]` | Column index to sort | `0`, `1`, `2` |
|
|
469
|
+
| `order[0][dir]` | Sort direction | `asc`, `desc` |
|
|
470
|
+
|
|
471
|
+
### Response Format
|
|
472
|
+
|
|
473
|
+
**Your backend should return:**
|
|
474
|
+
|
|
475
|
+
```json
|
|
476
|
+
{
|
|
477
|
+
"draw": 1,
|
|
478
|
+
"recordsTotal": 100,
|
|
479
|
+
"recordsFiltered": 50,
|
|
480
|
+
"data": [
|
|
481
|
+
{ "id": 1, "name": "John", "email": "john@example.com" }
|
|
482
|
+
]
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
| Field | Description |
|
|
487
|
+
|-------|-------------|
|
|
488
|
+
| `draw` | Echo back the request's draw parameter |
|
|
489
|
+
| `recordsTotal` | Total records before filtering |
|
|
490
|
+
| `recordsFiltered` | Total records after filtering/search |
|
|
491
|
+
| `data` | Array of data objects |
|
|
492
|
+
|
|
493
|
+
### Backend Implementation
|
|
494
|
+
|
|
495
|
+
#### With Yajra DataTables (Recommended)
|
|
496
|
+
|
|
497
|
+
```php
|
|
498
|
+
use Yajra\DataTables\Facades\DataTables;
|
|
499
|
+
|
|
500
|
+
public function getData(Request $request)
|
|
501
|
+
{
|
|
502
|
+
return DataTables::of(User::query())->make(true);
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### Manual Implementation
|
|
507
|
+
|
|
508
|
+
```php
|
|
509
|
+
public function getData(Request $request)
|
|
510
|
+
{
|
|
511
|
+
$query = User::query();
|
|
512
|
+
$recordsTotal = $query->count();
|
|
513
|
+
|
|
514
|
+
// Apply search
|
|
515
|
+
if ($search = $request->input('search.value')) {
|
|
516
|
+
$query->where('name', 'like', "%{$search}%");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
$recordsFiltered = $query->count();
|
|
520
|
+
|
|
521
|
+
// Apply sorting
|
|
522
|
+
if ($columnIndex = $request->input('order.0.column')) {
|
|
523
|
+
$columns = ['id', 'name', 'email', 'created_at'];
|
|
524
|
+
$column = $columns[$columnIndex] ?? 'id';
|
|
525
|
+
$dir = $request->input('order.0.dir', 'asc');
|
|
526
|
+
$query->orderBy($column, $dir);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Paginate
|
|
530
|
+
$start = $request->input('start', 0);
|
|
531
|
+
$length = $request->input('length', 10);
|
|
532
|
+
$data = $query->skip($start)->take($length)->get();
|
|
533
|
+
|
|
534
|
+
return response()->json([
|
|
535
|
+
'draw' => (int) $request->input('draw'),
|
|
536
|
+
'recordsTotal' => $recordsTotal,
|
|
537
|
+
'recordsFiltered' => $recordsFiltered,
|
|
538
|
+
'data' => $data
|
|
539
|
+
]);
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## ð Backend Integration
|
|
546
|
+
|
|
547
|
+
### Laravel (Standard Pagination)
|
|
548
|
+
|
|
549
|
+
```php
|
|
550
|
+
public function getData(Request $request)
|
|
551
|
+
{
|
|
552
|
+
$query = User::query();
|
|
553
|
+
|
|
554
|
+
// 1. Search
|
|
555
|
+
if ($search = $request->input('search')) {
|
|
556
|
+
$query->where('name', 'like', "%{$search}%")
|
|
557
|
+
->orWhere('email', 'like', "%{$search}%");
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// 2. Sort
|
|
561
|
+
if ($sort = $request->input('sort')) {
|
|
562
|
+
$query->orderBy($sort, $request->input('order', 'asc'));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// 3. Paginate
|
|
566
|
+
return response()->json($query->paginate($request->input('per_page', 10)));
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Expected Response
|
|
571
|
+
|
|
572
|
+
```json
|
|
573
|
+
{
|
|
574
|
+
"current_page": 1,
|
|
575
|
+
"data": [...],
|
|
576
|
+
"last_page": 10,
|
|
577
|
+
"per_page": 10,
|
|
578
|
+
"total": 100,
|
|
579
|
+
"from": 1,
|
|
580
|
+
"to": 10
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## ðĻ Styling Customization
|
|
587
|
+
|
|
588
|
+
### Row Colors
|
|
589
|
+
|
|
590
|
+
```vue
|
|
591
|
+
<SimpleTable
|
|
592
|
+
odd-row-color="bg-white"
|
|
593
|
+
even-row-color="bg-gray-50"
|
|
594
|
+
hover-color="hover:bg-blue-50"
|
|
595
|
+
/>
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### Tailwind Configuration
|
|
599
|
+
|
|
600
|
+
Ensure your `tailwind.config.js` includes these colors:
|
|
601
|
+
|
|
602
|
+
```javascript
|
|
603
|
+
module.exports = {
|
|
604
|
+
theme: {
|
|
605
|
+
extend: {
|
|
606
|
+
colors: {
|
|
607
|
+
border: "hsl(var(--border))",
|
|
608
|
+
input: "hsl(var(--input))",
|
|
609
|
+
ring: "hsl(var(--ring))",
|
|
610
|
+
background: "hsl(var(--background))",
|
|
611
|
+
foreground: "hsl(var(--foreground))",
|
|
612
|
+
primary: {
|
|
613
|
+
DEFAULT: "hsl(var(--primary))",
|
|
614
|
+
foreground: "hsl(var(--primary-foreground))",
|
|
615
|
+
},
|
|
616
|
+
muted: {
|
|
617
|
+
DEFAULT: "hsl(var(--muted))",
|
|
618
|
+
foreground: "hsl(var(--muted-foreground))",
|
|
619
|
+
},
|
|
620
|
+
accent: {
|
|
621
|
+
DEFAULT: "hsl(var(--accent))",
|
|
622
|
+
foreground: "hsl(var(--accent-foreground))",
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Or define CSS variables:
|
|
631
|
+
|
|
632
|
+
```css
|
|
633
|
+
:root {
|
|
634
|
+
--background: 0 0% 100%;
|
|
635
|
+
--foreground: 222.2 84% 4.9%;
|
|
636
|
+
--primary: 221.2 83.2% 53.3%;
|
|
637
|
+
--primary-foreground: 210 40% 98%;
|
|
638
|
+
--muted: 210 40% 96.1%;
|
|
639
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
640
|
+
--accent: 210 40% 96.1%;
|
|
641
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
642
|
+
--border: 214.3 31.8% 91.4%;
|
|
643
|
+
--input: 214.3 31.8% 91.4%;
|
|
644
|
+
--ring: 222.2 84% 4.9%;
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## ð Troubleshooting
|
|
651
|
+
|
|
652
|
+
### Data Not Loading
|
|
653
|
+
|
|
654
|
+
**Check:**
|
|
655
|
+
1. â
Is `fetch-url` correct?
|
|
656
|
+
2. â
Does backend return the right format?
|
|
657
|
+
3. â
Open Network tab - any errors?
|
|
658
|
+
4. â
CORS enabled on backend?
|
|
659
|
+
|
|
660
|
+
### Sorting Not Working
|
|
661
|
+
|
|
662
|
+
**For Laravel:**
|
|
663
|
+
```vue
|
|
664
|
+
<SimpleTable :columns="columns" />
|
|
665
|
+
<!-- Make sure sortable is set correctly -->
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
**For DataTables:**
|
|
669
|
+
```vue
|
|
670
|
+
<SimpleTable protocol="datatables" :columns="columns" />
|
|
671
|
+
<!-- Column index must match backend expectations -->
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Pagination Numbers Not Showing
|
|
675
|
+
|
|
676
|
+
Check your browser console for errors. The pagination feature requires the updated package (v1.0.3+).
|
|
677
|
+
|
|
678
|
+
### Cache Not Clearing
|
|
679
|
+
|
|
680
|
+
```vue
|
|
681
|
+
<script setup>
|
|
682
|
+
const table = ref()
|
|
683
|
+
|
|
684
|
+
// Manually clear cache
|
|
685
|
+
table.value?.clearCache()
|
|
686
|
+
table.value?.refresh()
|
|
687
|
+
</script>
|
|
688
|
+
|
|
689
|
+
<template>
|
|
690
|
+
<SimpleTable ref="table" enable-cache />
|
|
691
|
+
</template>
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## ð Events
|
|
697
|
+
|
|
698
|
+
| Event | Payload | Description |
|
|
699
|
+
|-------|---------|-------------|
|
|
700
|
+
| `@update:search` | `string` | Emitted when search query changes |
|
|
701
|
+
| `@update:sort` | `{ column, direction }` | Emitted when sort changes |
|
|
702
|
+
| `@page-change` | `number` | Emitted when page changes |
|
|
703
|
+
| `@export` | `{ format, data }` | Emitted when export is triggered |
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
## ðĪ Contributing
|
|
708
|
+
|
|
709
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## ð License
|
|
714
|
+
|
|
715
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
## ðĪ Author
|
|
720
|
+
|
|
721
|
+
**Ghandi Galila**
|
|
722
|
+
|
|
723
|
+
---
|
|
724
|
+
|
|
725
|
+
## ð Support
|
|
726
|
+
|
|
727
|
+
If you find this package helpful, please give it a â on GitHub!
|
|
728
|
+
|
|
729
|
+
---
|
|
730
|
+
|
|
731
|
+
**Made with âĪïļ for the Vue community**
|