Skip to content

Commit 2c64774

Browse files
committed
feat: ✨ Test ajout pagination tableau
1 parent 8252799 commit 2c64774

File tree

2 files changed

+242
-10
lines changed

2 files changed

+242
-10
lines changed

src/components/DsfrTable/DsfrTable.stories.ts

Lines changed: 159 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ export default {
2424
control: 'boolean',
2525
description: 'Indique si la balise caption doit être visible (`false`, défaut) ou cachée (`true`)',
2626
},
27+
pagination: {
28+
control: 'boolean',
29+
description: 'Intègre une pagination au tableau',
30+
},
2731
headers: {
2832
control: 'object',
2933
description: 'Liste des en-têtes du tableau (tableau de string). Il existe un slot nommé `headers` pour gérer les en-têtes avec d’autres composants. C’est la même props attendue par <a href="/?path=/docs/composants-tableau-en-t%C3%AAtes-de-tableau-dsfrtableheaders--en-tetes-de-tableau">DsfrTableHeaders</a>',
@@ -49,9 +53,9 @@ const rows = [
4953
[
5054
'EGAUD',
5155
'Pierre-Louis',
52-
'pierre.egaud@ninja.com',
53-
'01 02 03 04 05',
54-
'06 01 02 03 04',
56+
'pierre.egaud@gmail.com',
57+
'02 04 06 08 10',
58+
'06 05 04 03 02',
5559
{
5660
component: 'DsfrTag',
5761
label: 'Erreur',
@@ -66,9 +70,9 @@ const rows = [
6670
rowData: [
6771
'DEBROIZE',
6872
'Clément',
69-
'clement.debroize@ninja.com',
70-
'01 02 03 04 05',
71-
'06 01 02 03 04',
73+
'clement.debroize@gmail.com',
74+
'02 44 66 55 99',
75+
'07 88 77 22 33',
7276
{
7377
component: 'DsfrTag',
7478
label: 'Succès',
@@ -81,21 +85,166 @@ const rows = [
8185
'Stan',
8286
8387
{
84-
text: '01 02 03 04 05',
88+
text: '02 77 00 00 77',
8589
cellAttrs: {
8690
class: 'pointer',
8791
onClick: () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
8892
},
8993
},
90-
'06 01 02 03 04',
94+
'06 08 07 09 08',
95+
{
96+
component: 'DsfrTag',
97+
label: 'Info',
98+
class: 'info',
99+
},
100+
],
101+
[
102+
'MONTANA',
103+
'Tony',
104+
105+
'02 07 03 19 84',
106+
'06 07 03 19 84',
107+
{
108+
component: 'DsfrTag',
109+
label: 'Erreur',
110+
class: 'error',
111+
},
112+
],
113+
[
114+
'BOND',
115+
'James',
116+
117+
'02 00 07 19 62',
118+
'06 00 07 19 62',
119+
{
120+
component: 'DsfrTag',
121+
label: 'Succès',
122+
class: 'success',
123+
},
124+
],
125+
[
126+
'RAMBO',
127+
'John',
128+
129+
'02 00 00 19 82',
130+
'06 00 00 19 82',
131+
{
132+
component: 'DsfrTag',
133+
label: 'Info',
134+
class: 'info',
135+
},
136+
],
137+
[
138+
'CONNOR',
139+
'Sarah',
140+
141+
'02 00 00 19 84',
142+
'06 00 00 19 84',
143+
{
144+
component: 'DsfrTag',
145+
label: 'Erreur',
146+
class: 'error',
147+
},
148+
],
149+
[
150+
'KENOBI',
151+
'Obiwan',
152+
153+
'02 00 00 19 77',
154+
'06 00 00 19 77',
155+
{
156+
component: 'DsfrTag',
157+
label: 'Succès',
158+
class: 'success',
159+
},
160+
],
161+
[
162+
'KRUEGER',
163+
'Freddy',
164+
165+
'02 00 00 19 84',
166+
'06 00 00 19 84',
167+
{
168+
component: 'DsfrTag',
169+
label: 'Info',
170+
class: 'info',
171+
},
172+
],
173+
[
174+
'LEGRIS',
175+
'Gandalf',
176+
177+
'02 00 00 20 01',
178+
'06 00 00 20 01',
179+
{
180+
component: 'DsfrTag',
181+
label: 'Erreur',
182+
class: 'error',
183+
},
184+
],
185+
[
186+
'SÖZE',
187+
'Keyser',
188+
189+
'02 00 00 19 95',
190+
'06 00 00 19 95',
191+
{
192+
component: 'DsfrTag',
193+
label: 'Info',
194+
class: 'info',
195+
},
196+
],
197+
[
198+
'HUNT',
199+
'Ethan',
200+
201+
'02 00 00 19 96',
202+
'06 00 00 19 96',
203+
{
204+
component: 'DsfrTag',
205+
label: 'Erreur',
206+
class: 'error',
207+
},
208+
],
209+
[
210+
'HOLMES',
211+
'Sherlock',
212+
213+
'02 00 00 18 87',
214+
'06 00 00 18 87',
215+
{
216+
component: 'DsfrTag',
217+
label: 'Succès',
218+
class: 'success',
219+
},
220+
],
221+
[
222+
'JONES',
223+
'Indiana',
224+
225+
'02 00 00 19 81',
226+
'06 00 00 19 81',
91227
{
92228
component: 'DsfrTag',
93229
label: 'Info',
94230
class: 'info',
95231
},
96232
],
233+
[
234+
'WAYNE',
235+
'Bruce',
236+
237+
'02 00 00 19 89',
238+
'06 00 00 19 89',
239+
{
240+
component: 'DsfrTag',
241+
label: 'Erreur',
242+
class: 'error',
243+
},
244+
],
97245
]
98246
const noCaption = false
247+
const pagination = true
99248

100249
export const TableauEntier = (args) => ({
101250
components: {
@@ -120,6 +269,7 @@ export const TableauEntier = (args) => ({
120269
:headers="headers"
121270
:rows="rows"
122271
:no-caption="noCaption"
272+
:pagination="pagination"
123273
/>
124274
`,
125275

@@ -129,4 +279,5 @@ TableauEntier.args = {
129279
headers,
130280
rows,
131281
noCaption,
282+
pagination,
132283
}

src/components/DsfrTable/DsfrTable.vue

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<script lang="ts" setup>
2+
import { ref, watch, computed, onMounted } from 'vue'
23
import DsfrTableRow, { type DsfrTableRowProps } from './DsfrTableRow.vue'
34
import DsfrTableHeaders from './DsfrTableHeaders.vue'
45
import { type DsfrTableHeaderProps } from './DsfrTableHeader.vue'
56
6-
withDefaults(defineProps<{
7+
const props = withDefaults(defineProps<{
78
title?: string
89
headers?:(DsfrTableHeaderProps | string)[]
910
rows?: (DsfrTableRowProps | string)[]
1011
noCaption?: boolean
12+
pagination?: boolean
1113
}>(), {
1214
title: undefined,
1315
headers: () => [],
@@ -18,6 +20,29 @@ const getRowData = (row: (DsfrTableRowProps | string | ({component: string} & Re
1820
// @ts-ignore TODO: find a way to improve types here
1921
return row.rowData || row
2022
}
23+
24+
const currentPage = ref(1)
25+
const optionSelected = ref(10)
26+
const pageCount = ref(props.rows.length > optionSelected.value ? Math.ceil(props.rows.length / optionSelected.value) : 1)
27+
const paginationOptions = [5, 10, 25, 50, 100]
28+
const returnLowestLimit = () => currentPage.value * optionSelected.value - optionSelected.value
29+
const returnHighestLimit = () => currentPage.value * optionSelected.value
30+
let truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
31+
32+
watch(() => optionSelected.value, (newVal, OldVal) => {
33+
props.rows.length > optionSelected.value ? pageCount.value = Math.ceil(props.rows.length / newVal) : pageCount.value = 1
34+
truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
35+
})
36+
37+
watch(() => currentPage.value, (newVal, OldVal) => {
38+
truncatedResults = props.rows.slice(returnLowestLimit(), returnHighestLimit())
39+
})
40+
41+
const goFirstPage = () => { currentPage.value = 1 }
42+
const goPreviousPage = () => { currentPage.value > 1 ? currentPage.value -= 1 : currentPage.value }
43+
const goNextPage = () => { currentPage.value < pageCount.value ? currentPage.value += 1 : currentPage.value }
44+
const goLastPage = () => { currentPage.value = pageCount.value }
45+
2146
</script>
2247

2348
<template>
@@ -45,13 +70,69 @@ const getRowData = (row: (DsfrTableRowProps | string | ({component: string} & Re
4570
<slot />
4671
<template v-if="rows && rows.length">
4772
<DsfrTableRow
48-
v-for="(row, i) of rows"
73+
v-for="(row, i) of truncatedResults"
4974
:key="i"
5075
:row-data="getRowData(row)"
5176
:row-attrs="typeof row === 'string' ? {} : row.rowAttrs"
5277
/>
5378
</template>
79+
<tr v-if="pagination">
80+
<td :colspan="headers.length">
81+
<div class="flex justify-right">
82+
<div class="self-center">
83+
<span>Résultats par page : </span>
84+
<select
85+
v-model="optionSelected"
86+
>
87+
<option
88+
v-for="(option, idx) in paginationOptions"
89+
:key="idx"
90+
:value="option">
91+
{{ option }}
92+
</option>
93+
</select>
94+
</div>
95+
<div class="flex ml-1"><span class="self-center">Page {{ currentPage }} sur {{ pageCount }}</span></div>
96+
<div class="flex ml-1">
97+
<button
98+
class="fr-icon-arrow-left-s-first-line"
99+
@click="goFirstPage()"
100+
/>
101+
<button
102+
class="fr-icon-arrow-left-s-line-double"
103+
@click="goPreviousPage()"
104+
/>
105+
<button
106+
class="fr-icon-arrow-right-s-line-double"
107+
@click="goNextPage()"
108+
/>
109+
<button
110+
class="fr-icon-arrow-right-s-last-line"
111+
@click="goLastPage()"
112+
/>
113+
</div>
114+
</div>
115+
</td>
116+
</tr>
54117
</tbody>
55118
</table>
56119
</div>
57120
</template>
121+
122+
<style scoped>
123+
.flex {
124+
display: flex;
125+
}
126+
127+
.justify-right {
128+
justify-content: right;
129+
}
130+
131+
.ml-1 {
132+
margin-left: 1rem;
133+
}
134+
135+
.self-center {
136+
align-self: center;
137+
}
138+
</style>

0 commit comments

Comments
 (0)