@paris-ias/list 1.0.117 → 1.0.118
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/dist/module.json
CHANGED
|
@@ -3,93 +3,71 @@
|
|
|
3
3
|
value="currentPage"
|
|
4
4
|
role="navigation"
|
|
5
5
|
aria-label="Pagination Navigation"
|
|
6
|
+
class="d-inline-flex"
|
|
6
7
|
>
|
|
7
|
-
<!--
|
|
8
|
+
<!-- Previous button -->
|
|
8
9
|
<v-btn
|
|
9
|
-
v-if="!(hidePrevNext &&
|
|
10
|
-
:disabled="
|
|
10
|
+
v-if="!(hidePrevNext && isFirstPage)"
|
|
11
|
+
:disabled="isFirstPage"
|
|
11
12
|
min-width="35"
|
|
12
13
|
height="35"
|
|
13
14
|
width="35"
|
|
14
|
-
:tabindex="
|
|
15
|
+
:tabindex="isFirstPage && hidePrevNext ? -1 : 0"
|
|
15
16
|
aria-label="Previous Page"
|
|
16
|
-
|
|
17
|
-
@
|
|
18
|
-
@keyup.enter="updatePage(currentPage - 1)"
|
|
17
|
+
@click="onChange(currentPage - 1)"
|
|
18
|
+
@keyup.enter="onChange(currentPage - 1)"
|
|
19
19
|
>
|
|
20
20
|
<v-icon>mdi-chevron-left</v-icon>
|
|
21
21
|
</v-btn>
|
|
22
22
|
|
|
23
|
+
<!-- Page buttons and gaps -->
|
|
23
24
|
<template v-for="(page, index) in renderPages" :key="page.key">
|
|
25
|
+
<!-- Ellipsis gap -->
|
|
24
26
|
<v-btn
|
|
25
27
|
v-if="page.isGap"
|
|
28
|
+
icon
|
|
26
29
|
min-width="35"
|
|
27
30
|
height="35"
|
|
28
31
|
width="35"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@keyup.enter="updatePage(getGapPage(index))"
|
|
32
|
-
@click="updatePage(getGapPage(index))"
|
|
32
|
+
@click="onChange(getGapPage(index))"
|
|
33
|
+
@keyup.enter="onChange(getGapPage(index))"
|
|
33
34
|
>
|
|
34
35
|
...
|
|
35
36
|
</v-btn>
|
|
36
|
-
<template v-else>
|
|
37
|
-
<!-- <v-btn
|
|
38
|
-
:class="{ 'active-page': !!page.current }"
|
|
39
|
-
tabindex="0"
|
|
40
|
-
outlined
|
|
41
|
-
min-width="35"
|
|
42
|
-
height="35"
|
|
43
|
-
tile
|
|
44
|
-
nuxt
|
|
45
|
-
:active="!!page.current"
|
|
46
|
-
:color="!!page.current ? 'white' : 'black'"
|
|
47
|
-
text
|
|
48
|
-
width="35"
|
|
49
|
-
:aria-current="!!page.current ? 'true' : 'false'"
|
|
50
|
-
:aria-label="
|
|
51
|
-
page.current
|
|
52
|
-
? `Current page, Page ${page.value}`
|
|
53
|
-
: `Goto Page ${page.value}`
|
|
54
|
-
"
|
|
55
|
-
@click="updatePage(page.value)"
|
|
56
|
-
@keyup.enter="updatePage(page.value)"
|
|
57
|
-
>
|
|
58
|
-
{{ page.value }}
|
|
59
|
-
</v-btn> -->
|
|
60
37
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
38
|
+
<!-- Page number -->
|
|
39
|
+
<v-btn
|
|
40
|
+
v-else
|
|
41
|
+
:class="['page-button', { 'active-page': page.current }]"
|
|
42
|
+
tabindex="0"
|
|
43
|
+
min-width="35"
|
|
44
|
+
height="35"
|
|
45
|
+
tile
|
|
46
|
+
width="35"
|
|
47
|
+
:aria-current="page.current ? 'page' : undefined"
|
|
48
|
+
:aria-label="
|
|
49
|
+
page.current
|
|
50
|
+
? `Current page, Page ${page.value}`
|
|
51
|
+
: `Go to Page ${page.value}`
|
|
52
|
+
"
|
|
53
|
+
@click="onChange(page.value)"
|
|
54
|
+
@keyup.enter="onChange(page.value)"
|
|
55
|
+
>
|
|
56
|
+
{{ page.value }}
|
|
57
|
+
</v-btn>
|
|
80
58
|
</template>
|
|
81
59
|
|
|
60
|
+
<!-- Next button -->
|
|
82
61
|
<v-btn
|
|
83
|
-
v-if="!(hidePrevNext &&
|
|
84
|
-
:
|
|
85
|
-
:
|
|
62
|
+
v-if="!(hidePrevNext && isLastPage)"
|
|
63
|
+
:disabled="isLastPage"
|
|
64
|
+
:tabindex="isLastPage && hidePrevNext ? -1 : 0"
|
|
86
65
|
aria-label="Next Page"
|
|
87
66
|
min-width="35"
|
|
88
67
|
height="35"
|
|
89
68
|
width="35"
|
|
90
|
-
|
|
91
|
-
@
|
|
92
|
-
@keyup.enter="updatePage(currentPage + 1)"
|
|
69
|
+
@click="onChange(currentPage + 1)"
|
|
70
|
+
@keyup.enter="onChange(currentPage + 1)"
|
|
93
71
|
>
|
|
94
72
|
<v-icon>mdi-chevron-right</v-icon>
|
|
95
73
|
</v-btn>
|
|
@@ -97,117 +75,76 @@
|
|
|
97
75
|
</template>
|
|
98
76
|
|
|
99
77
|
<script setup>
|
|
100
|
-
import {
|
|
101
|
-
import { useRoute, computed, useI18n } from "#imports";
|
|
102
|
-
const { locale } = useI18n();
|
|
103
|
-
const route = useRoute();
|
|
104
|
-
const rootStore = useRootStore();
|
|
78
|
+
import { computed } from "vue";
|
|
105
79
|
const props = defineProps({
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
type: Number,
|
|
112
|
-
default: 1
|
|
113
|
-
},
|
|
114
|
-
pagePadding: {
|
|
115
|
-
type: Number,
|
|
116
|
-
default: 1,
|
|
117
|
-
validator: (value) => {
|
|
118
|
-
return value > 0;
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
pageGap: {
|
|
122
|
-
type: Number,
|
|
123
|
-
default: 2,
|
|
124
|
-
validator: (value) => {
|
|
125
|
-
return value > 0;
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
hidePrevNext: {
|
|
129
|
-
type: Boolean,
|
|
130
|
-
default: false
|
|
131
|
-
},
|
|
132
|
-
type: {
|
|
133
|
-
type: String,
|
|
134
|
-
default: "",
|
|
135
|
-
required: true
|
|
136
|
-
}
|
|
80
|
+
currentPage: { type: Number, required: true },
|
|
81
|
+
totalPages: { type: Number, required: true },
|
|
82
|
+
pagePadding: { type: Number, default: 1, validator: (v) => v > 0 },
|
|
83
|
+
pageGap: { type: Number, default: 2, validator: (v) => v > 0 },
|
|
84
|
+
hidePrevNext: { type: Boolean, default: false }
|
|
137
85
|
});
|
|
86
|
+
const emit = defineEmits(["update"]);
|
|
87
|
+
const isFirstPage = computed(() => props.currentPage === 1);
|
|
88
|
+
const isLastPage = computed(
|
|
89
|
+
() => props.currentPage === props.totalPages || props.totalPages === 0
|
|
90
|
+
);
|
|
138
91
|
const renderPages = computed(() => {
|
|
92
|
+
const createPage = (pageIndex) => ({
|
|
93
|
+
key: `page-${pageIndex}`,
|
|
94
|
+
value: pageIndex,
|
|
95
|
+
current: pageIndex === props.currentPage
|
|
96
|
+
});
|
|
97
|
+
const createGap = (pageIndex) => ({ key: `gap-${pageIndex}`, isGap: true });
|
|
139
98
|
const pages = [];
|
|
140
|
-
for (let
|
|
141
|
-
if (
|
|
142
|
-
pages.push(createPage(
|
|
99
|
+
for (let i = 1; i <= props.totalPages; i++) {
|
|
100
|
+
if (i === props.currentPage || i < props.pageGap || i > props.totalPages - props.pageGap + 1) {
|
|
101
|
+
pages.push(createPage(i));
|
|
143
102
|
continue;
|
|
144
103
|
}
|
|
145
|
-
let
|
|
146
|
-
let maximum;
|
|
104
|
+
let min, max;
|
|
147
105
|
if (props.currentPage <= props.pageGap + props.pagePadding) {
|
|
148
|
-
|
|
149
|
-
|
|
106
|
+
min = props.pageGap + 1;
|
|
107
|
+
max = min + props.pagePadding * 2;
|
|
150
108
|
} else if (props.currentPage >= props.totalPages - props.pageGap - props.pagePadding) {
|
|
151
|
-
|
|
152
|
-
|
|
109
|
+
max = props.totalPages - props.pageGap;
|
|
110
|
+
min = max - props.pagePadding * 2;
|
|
153
111
|
} else {
|
|
154
|
-
|
|
155
|
-
|
|
112
|
+
min = props.currentPage - props.pagePadding;
|
|
113
|
+
max = props.currentPage + props.pagePadding;
|
|
156
114
|
}
|
|
157
|
-
if (
|
|
158
|
-
pages.push(createPage(
|
|
115
|
+
if (i >= min && i <= props.currentPage || i <= max && i >= props.currentPage) {
|
|
116
|
+
pages.push(createPage(i));
|
|
159
117
|
continue;
|
|
160
118
|
}
|
|
161
|
-
if (
|
|
162
|
-
if (
|
|
163
|
-
pages.push(createGap(
|
|
119
|
+
if (i === props.pageGap) {
|
|
120
|
+
if (min > props.pageGap + 1 && props.currentPage > props.pageGap + props.pagePadding + 1) {
|
|
121
|
+
pages.push(createGap(i));
|
|
164
122
|
} else {
|
|
165
|
-
pages.push(createPage(
|
|
123
|
+
pages.push(createPage(i));
|
|
166
124
|
}
|
|
167
125
|
continue;
|
|
168
126
|
}
|
|
169
|
-
if (
|
|
170
|
-
if (
|
|
171
|
-
pages.push(createGap(
|
|
127
|
+
if (i === props.totalPages - props.pageGap + 1) {
|
|
128
|
+
if (max < props.totalPages - props.pageGap && props.currentPage < props.totalPages - props.pageGap - props.pagePadding) {
|
|
129
|
+
pages.push(createGap(i));
|
|
172
130
|
} else {
|
|
173
|
-
pages.push(createPage(
|
|
131
|
+
pages.push(createPage(i));
|
|
174
132
|
}
|
|
175
133
|
continue;
|
|
176
134
|
}
|
|
177
135
|
}
|
|
178
136
|
return pages;
|
|
179
137
|
});
|
|
180
|
-
const createPage = (pageIndex) => {
|
|
181
|
-
return {
|
|
182
|
-
key: pageIndex,
|
|
183
|
-
current: props.currentPage === pageIndex,
|
|
184
|
-
value: pageIndex
|
|
185
|
-
};
|
|
186
|
-
};
|
|
187
|
-
const firstPageSelected = () => {
|
|
188
|
-
return props.currentPage === 1;
|
|
189
|
-
};
|
|
190
|
-
const lastPageSelected = () => {
|
|
191
|
-
return props.currentPage === props.totalPages || props.totalPages === 0;
|
|
192
|
-
};
|
|
193
|
-
const createGap = (pageIndex) => {
|
|
194
|
-
return {
|
|
195
|
-
key: pageIndex,
|
|
196
|
-
isGap: true
|
|
197
|
-
};
|
|
198
|
-
};
|
|
199
|
-
const emit = defineEmits(["update"]);
|
|
200
|
-
const updatePage = (page) => {
|
|
201
|
-
rootStore.updatePage({ page, type: props.type, lang: locale.value });
|
|
202
|
-
emit("update", page);
|
|
203
|
-
};
|
|
204
138
|
const getGapPage = (index) => {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
);
|
|
139
|
+
const before = renderPages.value[index - 1];
|
|
140
|
+
const after = renderPages.value[index + 1] || { value: props.totalPages };
|
|
141
|
+
return Math.floor((before.value + after.value) / 2);
|
|
208
142
|
};
|
|
143
|
+
function onChange(page) {
|
|
144
|
+
emit("update", page);
|
|
145
|
+
}
|
|
209
146
|
</script>
|
|
210
147
|
|
|
211
|
-
<style>
|
|
148
|
+
<style scoped>
|
|
212
149
|
.page-button{background-color:transparent;border:1px solid rgba(0,0,0,.2);color:#000;transition:background-color .3s ease,color .3s ease,transform .2s ease}.page-button:hover{background-color:#f0f0f0}.page-button.active-page{background-color:#000!important;color:#fff!important;transform:scale(1.05)}.page-button:focus{box-shadow:0 0 0 2px rgba(0,0,0,.3);outline:none}
|
|
213
150
|
</style>
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
</template>
|
|
33
33
|
|
|
34
34
|
<script setup>
|
|
35
|
+
import { nextTick } from "vue";
|
|
35
36
|
import { useRootStore } from "../../../stores/root";
|
|
36
37
|
import { capitalize } from "../../../composables/useUtils";
|
|
37
38
|
import {
|
|
@@ -91,26 +92,53 @@ const itemTemplate = computed(
|
|
|
91
92
|
)
|
|
92
93
|
);
|
|
93
94
|
const numberOfPages = computed(() => $stores[props.type].numberOfPages);
|
|
94
|
-
const page = computed(() =>
|
|
95
|
+
const page = computed(() => {
|
|
96
|
+
const p = parseInt(route.query.page, 10);
|
|
97
|
+
return !isNaN(p) && p > 0 ? p : 1;
|
|
98
|
+
});
|
|
95
99
|
const items = computed(() => $stores[props.type].items);
|
|
96
100
|
console.log("setup list");
|
|
97
|
-
onMounted(() => {
|
|
98
|
-
|
|
101
|
+
onMounted(async () => {
|
|
102
|
+
rootStore.loadRouteQuery(props.type);
|
|
103
|
+
const pageParam = parseInt(route.query.page, 10);
|
|
104
|
+
if (!isNaN(pageParam) && pageParam > 1) {
|
|
105
|
+
await rootStore.updatePage({
|
|
106
|
+
page: pageParam,
|
|
107
|
+
type: props.type,
|
|
108
|
+
lang: locale.value
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await rootStore.update(props.type, locale.value);
|
|
113
|
+
} catch (e) {
|
|
114
|
+
console.error("Error fetching list:", e);
|
|
115
|
+
}
|
|
99
116
|
});
|
|
100
|
-
rootStore.loadRouteQuery(props.type);
|
|
101
117
|
try {
|
|
102
118
|
await rootStore.update(props.type, locale.value);
|
|
103
119
|
} catch (error) {
|
|
104
120
|
console.log("error fetching update list: ", error);
|
|
105
121
|
}
|
|
122
|
+
watch(
|
|
123
|
+
() => page.value,
|
|
124
|
+
async (newPage) => {
|
|
125
|
+
const query = {
|
|
126
|
+
...route.query,
|
|
127
|
+
page: newPage > 1 ? String(newPage) : void 0
|
|
128
|
+
};
|
|
129
|
+
navigateTo({ query }, { replace: true });
|
|
130
|
+
await nextTick();
|
|
131
|
+
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
132
|
+
}
|
|
133
|
+
);
|
|
106
134
|
onBeforeUnmount(() => {
|
|
107
135
|
rootStore.resetState(props.type, locale.value);
|
|
108
136
|
});
|
|
109
|
-
|
|
110
|
-
rootStore.updatePage({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
137
|
+
async function onPageChange(newPage) {
|
|
138
|
+
await rootStore.updatePage({
|
|
139
|
+
page: newPage,
|
|
140
|
+
type: props.type,
|
|
141
|
+
lang: locale.value
|
|
114
142
|
});
|
|
115
|
-
}
|
|
143
|
+
}
|
|
116
144
|
</script>
|