@paris-ias/list 1.0.137 → 1.0.138
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 +1 -1
- package/dist/runtime/components/actions/DenseItem.vue +64 -0
- package/dist/runtime/components/actions/ExpandedItem.vue +17 -14
- package/dist/runtime/components/actions/RowsItem.vue +56 -10
- package/dist/runtime/components/actions/View.vue +5 -17
- package/dist/runtime/components/affiliation/DenseItem.vue +26 -10
- package/dist/runtime/components/affiliation/RowsItem.vue +26 -10
- package/dist/runtime/components/apps/DenseItem.vue +26 -10
- package/dist/runtime/components/apps/RowsItem.vue +26 -10
- package/dist/runtime/components/disciplines/DenseItem.vue +26 -10
- package/dist/runtime/components/disciplines/RowsItem.vue +26 -10
- package/dist/runtime/components/events/DenseItem.vue +12 -3
- package/dist/runtime/components/events/RowsItem.vue +12 -5
- package/dist/runtime/components/fellowships/DenseItem.vue +14 -0
- package/dist/runtime/components/fellowships/RowsItem.vue +16 -2
- package/dist/runtime/components/fellowships/View.vue +2 -2
- package/dist/runtime/components/files/DenseItem.vue +25 -10
- package/dist/runtime/components/files/RowsItem.vue +26 -10
- package/dist/runtime/components/list/atoms/FiltersMenu.vue +9 -0
- package/dist/runtime/components/list/atoms/PerPage.vue +3 -2
- package/dist/runtime/components/list/atoms/ResetButton.vue +5 -1
- package/dist/runtime/components/list/atoms/SearchInput.vue +15 -2
- package/dist/runtime/components/list/atoms/SearchString.vue +169 -133
- package/dist/runtime/components/list/atoms/SortMenu.vue +22 -18
- package/dist/runtime/components/list/atoms/ViewMenu.vue +26 -14
- package/dist/runtime/components/list/molecules/Filters.vue +4 -4
- package/dist/runtime/components/list/molecules/Header.vue +10 -19
- package/dist/runtime/components/list/molecules/Pagination.vue +51 -48
- package/dist/runtime/components/list/organisms/List.vue +93 -73
- package/dist/runtime/components/mailing/RowsItem.vue +26 -10
- package/dist/runtime/components/news/DenseItem.vue +59 -45
- package/dist/runtime/components/news/RowsItem.vue +11 -7
- package/dist/runtime/components/people/DenseItem.vue +10 -8
- package/dist/runtime/components/people/RowsItem.vue +11 -2
- package/dist/runtime/components/projects/DenseItem.vue +11 -4
- package/dist/runtime/components/projects/RowsItem.vue +10 -3
- package/dist/runtime/components/publications/DenseItem.vue +12 -8
- package/dist/runtime/components/publications/RowsItem.vue +12 -4
- package/dist/runtime/components/tags/RowsItem.vue +23 -10
- package/dist/runtime/components/users/DenseItem.vue +24 -10
- package/dist/runtime/components/users/RowsItem.vue +24 -10
- package/dist/runtime/composables/useUtils.js +1 -1
- package/dist/runtime/plugins/pinia.js +5 -2
- package/dist/runtime/stores/root.d.ts +10 -9
- package/dist/runtime/stores/root.js +82 -117
- package/package.json +1 -1
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-menu>
|
|
2
|
+
<v-menu :disabled="$stores[type].loading">
|
|
3
3
|
<template #activator="{ props: menu }">
|
|
4
4
|
<v-tooltip location="top">
|
|
5
5
|
<template #activator="{ props: tooltip }">
|
|
6
|
-
<v-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
<template v-if="$stores[type].loading">
|
|
7
|
+
<v-skeleton-loader type="button" :class="{ 'mt-3': isXsDisplay }" />
|
|
8
|
+
</template>
|
|
9
|
+
<template v-else>
|
|
10
|
+
<v-btn
|
|
11
|
+
x-large
|
|
12
|
+
tile
|
|
13
|
+
flat
|
|
14
|
+
:icon="'mdi-' + (current?.icon || defaultView?.icon)"
|
|
15
|
+
:class="{ 'mt-3': isXsDisplay }"
|
|
16
|
+
v-bind="mergeProps(menu, tooltip)"
|
|
17
|
+
/>
|
|
18
|
+
</template>
|
|
16
19
|
</template>
|
|
17
20
|
<div
|
|
18
21
|
v-html="
|
|
19
22
|
$t('list.view-mode') +
|
|
20
|
-
$t('list.' + current
|
|
23
|
+
$t('list.' + (current?.name || defaultView?.name))
|
|
21
24
|
"
|
|
22
25
|
/>
|
|
23
26
|
</v-tooltip>
|
|
@@ -26,6 +29,7 @@
|
|
|
26
29
|
<v-list-item
|
|
27
30
|
v-for="(value, key, index) in items"
|
|
28
31
|
:key="index"
|
|
32
|
+
:disabled="$stores[type].loading"
|
|
29
33
|
@click="updateView(value.name || key)"
|
|
30
34
|
>
|
|
31
35
|
<template #prepend>
|
|
@@ -43,7 +47,7 @@
|
|
|
43
47
|
import { mergeProps } from "vue"
|
|
44
48
|
import { useDisplay } from "vuetify"
|
|
45
49
|
import { useRootStore } from "../../../stores/root"
|
|
46
|
-
import { useNuxtApp, ref, useI18n } from "#imports"
|
|
50
|
+
import { useNuxtApp, ref, useI18n, computed } from "#imports"
|
|
47
51
|
const { locale } = useI18n()
|
|
48
52
|
const { $stores } = useNuxtApp()
|
|
49
53
|
|
|
@@ -61,8 +65,16 @@ const items = ref($stores[props.type].views)
|
|
|
61
65
|
|
|
62
66
|
const current = ref($stores[props.type].view)
|
|
63
67
|
|
|
68
|
+
const defaultView = ref(
|
|
69
|
+
$stores[props.type].views[
|
|
70
|
+
Object.keys($stores[props.type].views).find(
|
|
71
|
+
(k) => $stores[props.type].views[k]?.default === true,
|
|
72
|
+
)
|
|
73
|
+
] || { name: "list", icon: "view-list" },
|
|
74
|
+
)
|
|
75
|
+
|
|
64
76
|
const updateView = async (value) => {
|
|
65
|
-
|
|
77
|
+
rootStore.updateView({ value, type: props.type, lang: locale.value })
|
|
66
78
|
}
|
|
67
79
|
</script>
|
|
68
80
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-row>
|
|
3
|
-
<template v-for="filterItem in Object.keys($stores[type].filters)">
|
|
3
|
+
<template v-for="(filterItem, index) in Object.keys($stores[type].filters)">
|
|
4
4
|
<v-col
|
|
5
5
|
v-if="computeVisibility(filterItem)"
|
|
6
|
-
:key="type + filterItem"
|
|
6
|
+
:key="type + index + filterItem"
|
|
7
7
|
cols="12"
|
|
8
8
|
sm="6"
|
|
9
9
|
md="4"
|
|
10
10
|
>
|
|
11
11
|
<component
|
|
12
12
|
:is="ComponentName(filterItem)"
|
|
13
|
+
:id="type + index + filterItem"
|
|
13
14
|
tile
|
|
14
15
|
:name="filterItem"
|
|
15
16
|
hide-details
|
|
@@ -53,7 +54,6 @@ const getItems = (name) => {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
if ($filters?.[props.type]?.[name]) {
|
|
56
|
-
/* console.log("filters found for ", name, $filters[props.type][name]) */
|
|
57
57
|
return $filters[props.type][name]
|
|
58
58
|
.filter((key) => key !== "label")
|
|
59
59
|
.map((item) => ({
|
|
@@ -68,7 +68,7 @@ const getItems = (name) => {
|
|
|
68
68
|
if (
|
|
69
69
|
messages.value[locale.value].list.filters[props.type][name] === undefined
|
|
70
70
|
) {
|
|
71
|
-
console.log("name not found, no item for this
|
|
71
|
+
console.log("name not found, no item for this filter: ", name)
|
|
72
72
|
return []
|
|
73
73
|
}
|
|
74
74
|
// TODO replace with package based values
|
|
@@ -34,25 +34,6 @@ import { ref, computed } from "vue"
|
|
|
34
34
|
import { useNuxtApp } from "#imports"
|
|
35
35
|
const { $stores } = useNuxtApp()
|
|
36
36
|
|
|
37
|
-
const filtersOpen = ref(false)
|
|
38
|
-
const visible = computed(() => {
|
|
39
|
-
console.log(
|
|
40
|
-
"$stores[props.type]?.filtersCount > 0: ",
|
|
41
|
-
$stores[props.type]?.filtersCount > 0
|
|
42
|
-
)
|
|
43
|
-
console.log(
|
|
44
|
-
"$stores[props.type]?.filtersCount: ",
|
|
45
|
-
$stores[props.type]?.filtersCount
|
|
46
|
-
)
|
|
47
|
-
console.log(
|
|
48
|
-
!!(
|
|
49
|
-
$stores[props.type]?.filtersCount && $stores[props.type]?.filtersCount > 0
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
return !!(
|
|
53
|
-
$stores[props.type]?.filtersCount && $stores[props.type]?.filtersCount > 0
|
|
54
|
-
)
|
|
55
|
-
})
|
|
56
37
|
const props = defineProps({
|
|
57
38
|
type: {
|
|
58
39
|
type: String,
|
|
@@ -60,4 +41,14 @@ const props = defineProps({
|
|
|
60
41
|
default: "",
|
|
61
42
|
},
|
|
62
43
|
})
|
|
44
|
+
const visible = computed(() => {
|
|
45
|
+
console.log(
|
|
46
|
+
"SHOULD DISPLAY FILTERS:",
|
|
47
|
+
$stores[props.type]?.filtersCount && $stores[props.type]?.filtersCount > 0,
|
|
48
|
+
)
|
|
49
|
+
return !!(
|
|
50
|
+
$stores[props.type]?.filtersCount && $stores[props.type]?.filtersCount > 0
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
const filtersOpen = ref(unref(visible))
|
|
63
54
|
</script>
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
<v-btn
|
|
10
10
|
v-if="!(hidePrevNext && isFirstPage)"
|
|
11
11
|
:disabled="isFirstPage"
|
|
12
|
-
min-width="
|
|
13
|
-
height="
|
|
14
|
-
width="
|
|
12
|
+
min-width="40"
|
|
13
|
+
height="40"
|
|
14
|
+
width="40"
|
|
15
|
+
class="prev-btn"
|
|
15
16
|
:tabindex="isFirstPage && hidePrevNext ? -1 : 0"
|
|
16
17
|
aria-label="Previous Page"
|
|
17
18
|
@click="onChange(currentPage - 1)"
|
|
@@ -19,16 +20,16 @@
|
|
|
19
20
|
>
|
|
20
21
|
<v-icon>mdi-chevron-left</v-icon>
|
|
21
22
|
</v-btn>
|
|
22
|
-
|
|
23
23
|
<!-- Page buttons and gaps -->
|
|
24
24
|
<template v-for="(page, index) in renderPages" :key="page.key">
|
|
25
25
|
<!-- Ellipsis gap -->
|
|
26
26
|
<v-btn
|
|
27
|
+
class="ellipsis-btn"
|
|
27
28
|
v-if="page.isGap"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
height="
|
|
31
|
-
width="
|
|
29
|
+
min-width="40"
|
|
30
|
+
tile
|
|
31
|
+
height="40"
|
|
32
|
+
width="40"
|
|
32
33
|
@click="onChange(getGapPage(index))"
|
|
33
34
|
@keyup.enter="onChange(getGapPage(index))"
|
|
34
35
|
>
|
|
@@ -40,10 +41,10 @@
|
|
|
40
41
|
v-else
|
|
41
42
|
:class="['page-button', { 'active-page': page.current }]"
|
|
42
43
|
tabindex="0"
|
|
43
|
-
min-width="
|
|
44
|
-
height="
|
|
44
|
+
min-width="40"
|
|
45
|
+
height="40"
|
|
45
46
|
tile
|
|
46
|
-
width="
|
|
47
|
+
width="40"
|
|
47
48
|
:aria-current="page.current ? 'page' : undefined"
|
|
48
49
|
:aria-label="
|
|
49
50
|
page.current
|
|
@@ -63,9 +64,11 @@
|
|
|
63
64
|
:disabled="isLastPage"
|
|
64
65
|
:tabindex="isLastPage && hidePrevNext ? -1 : 0"
|
|
65
66
|
aria-label="Next Page"
|
|
66
|
-
min-width="
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
min-width="40"
|
|
68
|
+
tile
|
|
69
|
+
class="next-btn"
|
|
70
|
+
height="40"
|
|
71
|
+
width="40"
|
|
69
72
|
@click="onChange(currentPage + 1)"
|
|
70
73
|
@keyup.enter="onChange(currentPage + 1)"
|
|
71
74
|
>
|
|
@@ -75,7 +78,7 @@
|
|
|
75
78
|
</template>
|
|
76
79
|
|
|
77
80
|
<script setup>
|
|
78
|
-
import { computed } from "vue"
|
|
81
|
+
import { computed } from "vue"
|
|
79
82
|
|
|
80
83
|
const props = defineProps({
|
|
81
84
|
currentPage: { type: Number, required: true },
|
|
@@ -83,15 +86,15 @@ const props = defineProps({
|
|
|
83
86
|
pagePadding: { type: Number, default: 1, validator: (v) => v > 0 },
|
|
84
87
|
pageGap: { type: Number, default: 2, validator: (v) => v > 0 },
|
|
85
88
|
hidePrevNext: { type: Boolean, default: false },
|
|
86
|
-
})
|
|
89
|
+
})
|
|
87
90
|
|
|
88
|
-
const emit = defineEmits(["update"])
|
|
91
|
+
const emit = defineEmits(["update"])
|
|
89
92
|
|
|
90
93
|
// Computed state for prev/next disabled
|
|
91
|
-
const isFirstPage = computed(() => props.currentPage === 1)
|
|
94
|
+
const isFirstPage = computed(() => props.currentPage === 1)
|
|
92
95
|
const isLastPage = computed(
|
|
93
|
-
() => props.currentPage === props.totalPages || props.totalPages === 0
|
|
94
|
-
)
|
|
96
|
+
() => props.currentPage === props.totalPages || props.totalPages === 0,
|
|
97
|
+
)
|
|
95
98
|
|
|
96
99
|
// Generate pages and gap positions
|
|
97
100
|
const renderPages = computed(() => {
|
|
@@ -99,41 +102,41 @@ const renderPages = computed(() => {
|
|
|
99
102
|
key: `page-${pageIndex}`,
|
|
100
103
|
value: pageIndex,
|
|
101
104
|
current: pageIndex === props.currentPage,
|
|
102
|
-
})
|
|
103
|
-
const createGap = (pageIndex) => ({ key: `gap-${pageIndex}`, isGap: true })
|
|
105
|
+
})
|
|
106
|
+
const createGap = (pageIndex) => ({ key: `gap-${pageIndex}`, isGap: true })
|
|
104
107
|
|
|
105
|
-
const pages = []
|
|
108
|
+
const pages = []
|
|
106
109
|
for (let i = 1; i <= props.totalPages; i++) {
|
|
107
110
|
if (
|
|
108
111
|
i === props.currentPage ||
|
|
109
112
|
i < props.pageGap ||
|
|
110
113
|
i > props.totalPages - props.pageGap + 1
|
|
111
114
|
) {
|
|
112
|
-
pages.push(createPage(i))
|
|
113
|
-
continue
|
|
115
|
+
pages.push(createPage(i))
|
|
116
|
+
continue
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
let min, max
|
|
119
|
+
let min, max
|
|
117
120
|
if (props.currentPage <= props.pageGap + props.pagePadding) {
|
|
118
|
-
min = props.pageGap + 1
|
|
119
|
-
max = min + props.pagePadding * 2
|
|
121
|
+
min = props.pageGap + 1
|
|
122
|
+
max = min + props.pagePadding * 2
|
|
120
123
|
} else if (
|
|
121
124
|
props.currentPage >=
|
|
122
125
|
props.totalPages - props.pageGap - props.pagePadding
|
|
123
126
|
) {
|
|
124
|
-
max = props.totalPages - props.pageGap
|
|
125
|
-
min = max - props.pagePadding * 2
|
|
127
|
+
max = props.totalPages - props.pageGap
|
|
128
|
+
min = max - props.pagePadding * 2
|
|
126
129
|
} else {
|
|
127
|
-
min = props.currentPage - props.pagePadding
|
|
128
|
-
max = props.currentPage + props.pagePadding
|
|
130
|
+
min = props.currentPage - props.pagePadding
|
|
131
|
+
max = props.currentPage + props.pagePadding
|
|
129
132
|
}
|
|
130
133
|
|
|
131
134
|
if (
|
|
132
135
|
(i >= min && i <= props.currentPage) ||
|
|
133
136
|
(i <= max && i >= props.currentPage)
|
|
134
137
|
) {
|
|
135
|
-
pages.push(createPage(i))
|
|
136
|
-
continue
|
|
138
|
+
pages.push(createPage(i))
|
|
139
|
+
continue
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
if (i === props.pageGap) {
|
|
@@ -141,11 +144,11 @@ const renderPages = computed(() => {
|
|
|
141
144
|
min > props.pageGap + 1 &&
|
|
142
145
|
props.currentPage > props.pageGap + props.pagePadding + 1
|
|
143
146
|
) {
|
|
144
|
-
pages.push(createGap(i))
|
|
147
|
+
pages.push(createGap(i))
|
|
145
148
|
} else {
|
|
146
|
-
pages.push(createPage(i))
|
|
149
|
+
pages.push(createPage(i))
|
|
147
150
|
}
|
|
148
|
-
continue
|
|
151
|
+
continue
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
if (i === props.totalPages - props.pageGap + 1) {
|
|
@@ -153,28 +156,28 @@ const renderPages = computed(() => {
|
|
|
153
156
|
max < props.totalPages - props.pageGap &&
|
|
154
157
|
props.currentPage < props.totalPages - props.pageGap - props.pagePadding
|
|
155
158
|
) {
|
|
156
|
-
pages.push(createGap(i))
|
|
159
|
+
pages.push(createGap(i))
|
|
157
160
|
} else {
|
|
158
|
-
pages.push(createPage(i))
|
|
161
|
+
pages.push(createPage(i))
|
|
159
162
|
}
|
|
160
|
-
continue
|
|
163
|
+
continue
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
|
-
return pages
|
|
164
|
-
})
|
|
166
|
+
return pages
|
|
167
|
+
})
|
|
165
168
|
|
|
166
169
|
// Calculate page to jump when clicking gap
|
|
167
170
|
const getGapPage = (index) => {
|
|
168
|
-
const before = renderPages.value[index - 1]
|
|
169
|
-
const after = renderPages.value[index + 1] || { value: props.totalPages }
|
|
170
|
-
return Math.floor((before.value + after.value) / 2)
|
|
171
|
-
}
|
|
171
|
+
const before = renderPages.value[index - 1]
|
|
172
|
+
const after = renderPages.value[index + 1] || { value: props.totalPages }
|
|
173
|
+
return Math.floor((before.value + after.value) / 2)
|
|
174
|
+
}
|
|
172
175
|
|
|
173
176
|
function onChange(page) {
|
|
174
|
-
emit("update", page)
|
|
177
|
+
emit("update", page)
|
|
175
178
|
}
|
|
176
179
|
</script>
|
|
177
180
|
|
|
178
181
|
<style scoped>
|
|
179
|
-
.page-button{background-color:transparent;border:1px solid rgba(0,0,0,.2);
|
|
182
|
+
.ellipsis-btn,.next-btn,.page-button,.prev-btn{background-color:transparent;border:1px solid rgba(0,0,0,.2);font-size:16px;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}
|
|
180
183
|
</style>
|
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<ListMoleculesHeader :type="type" />
|
|
3
|
-
<component
|
|
3
|
+
<component
|
|
4
|
+
:is="view"
|
|
5
|
+
:loading="$stores[type] && $stores[type].loading && pending"
|
|
6
|
+
>
|
|
4
7
|
<component
|
|
5
8
|
:is="itemTemplate"
|
|
6
9
|
v-for="(item, index) in items"
|
|
7
|
-
:key="index"
|
|
8
|
-
:item
|
|
9
|
-
:index
|
|
10
|
+
:key="(item.name || item.lastname) + type + index"
|
|
11
|
+
:item
|
|
12
|
+
:index
|
|
13
|
+
:loading="$stores[type] && $stores[type].loading && pending"
|
|
10
14
|
:pathPrefix="
|
|
11
|
-
localePath({
|
|
12
|
-
name: pathPrefix,
|
|
13
|
-
params: { slug: item.slug },
|
|
14
|
-
})
|
|
15
|
+
localePath({ name: pathPrefix, params: { slug: item.slug } })
|
|
15
16
|
"
|
|
16
17
|
/>
|
|
17
18
|
</component>
|
|
18
19
|
<div class="text-center">
|
|
19
|
-
<ListAtomsPerPage
|
|
20
|
-
v-if="numberOfPages > 1"
|
|
21
|
-
:type="type"
|
|
22
|
-
class="float-right"
|
|
23
|
-
/>
|
|
20
|
+
<ListAtomsPerPage :type="type" class="float-right" />
|
|
24
21
|
|
|
25
22
|
<ListMoleculesPagination
|
|
26
|
-
v-if="numberOfPages > 1"
|
|
27
|
-
:type
|
|
28
|
-
color="black"
|
|
23
|
+
v-if="$stores[type].numberOfPages > 1"
|
|
24
|
+
:type
|
|
29
25
|
large
|
|
30
|
-
:current-page="page"
|
|
31
|
-
:total-pages="numberOfPages"
|
|
26
|
+
:current-page="$stores[type].page"
|
|
27
|
+
:total-pages="$stores[type].numberOfPages"
|
|
32
28
|
:page-padding="1"
|
|
33
29
|
:page-gap="2"
|
|
34
30
|
:hide-prev-next="false"
|
|
@@ -38,21 +34,20 @@
|
|
|
38
34
|
</template>
|
|
39
35
|
|
|
40
36
|
<script setup>
|
|
41
|
-
import {
|
|
37
|
+
import { computed, onUpdated, onMounted, watch } from "vue"
|
|
42
38
|
import { useRootStore } from "../../../stores/root"
|
|
43
39
|
import { capitalize } from "../../../composables/useUtils"
|
|
44
40
|
import {
|
|
45
41
|
useNuxtApp,
|
|
46
42
|
resolveComponent,
|
|
47
|
-
computed,
|
|
48
43
|
onBeforeUnmount,
|
|
49
|
-
onMounted,
|
|
50
44
|
useI18n,
|
|
51
45
|
useRoute,
|
|
52
|
-
navigateTo,
|
|
53
46
|
useLocalePath,
|
|
47
|
+
useAsyncQuery,
|
|
54
48
|
} from "#imports"
|
|
55
|
-
|
|
49
|
+
|
|
50
|
+
const { $stores, $queries } = useNuxtApp()
|
|
56
51
|
const { locale } = useI18n()
|
|
57
52
|
const route = useRoute()
|
|
58
53
|
const rootStore = useRootStore()
|
|
@@ -69,7 +64,7 @@ const props = defineProps({
|
|
|
69
64
|
default: "people",
|
|
70
65
|
required: true,
|
|
71
66
|
},
|
|
72
|
-
layout: {
|
|
67
|
+
/* layout: {
|
|
73
68
|
type: Object,
|
|
74
69
|
required: false,
|
|
75
70
|
default: () => {
|
|
@@ -78,94 +73,119 @@ const props = defineProps({
|
|
|
78
73
|
xl: 12,
|
|
79
74
|
}
|
|
80
75
|
},
|
|
81
|
-
},
|
|
76
|
+
}, */
|
|
82
77
|
pathPrefix: {
|
|
83
78
|
type: String,
|
|
84
79
|
required: true,
|
|
85
80
|
},
|
|
86
|
-
|
|
87
|
-
type: Object,
|
|
88
|
-
required: false,
|
|
89
|
-
default: () => {
|
|
90
|
-
return {}
|
|
91
|
-
},
|
|
92
|
-
},
|
|
81
|
+
|
|
93
82
|
addButton: {
|
|
94
83
|
type: Boolean,
|
|
95
84
|
required: false,
|
|
96
85
|
default: false,
|
|
97
86
|
},
|
|
98
|
-
items: [Object],
|
|
99
87
|
})
|
|
100
88
|
|
|
89
|
+
// Initialize loading state
|
|
90
|
+
console.log("start llocal loading from setup")
|
|
91
|
+
rootStore.setLoading(true, props.type)
|
|
92
|
+
|
|
93
|
+
// Initial route -> store (single source-of-truth on first load)
|
|
94
|
+
rootStore.loadRouteQuery(props.type)
|
|
95
|
+
|
|
96
|
+
// Computed properties for dynamic components
|
|
101
97
|
const view = computed(() =>
|
|
102
98
|
props.customView
|
|
103
99
|
? resolveComponent("ListViews" + capitalize(props.customView))
|
|
104
|
-
: resolveComponent(
|
|
100
|
+
: resolveComponent(
|
|
101
|
+
"ListViews" + capitalize($stores[props.type]?.view?.name || "list"),
|
|
102
|
+
),
|
|
105
103
|
)
|
|
106
104
|
const itemTemplate = computed(() =>
|
|
107
105
|
resolveComponent(
|
|
108
106
|
(
|
|
109
107
|
capitalize(props.type) +
|
|
110
|
-
capitalize($stores[props.type]
|
|
108
|
+
capitalize($stores[props.type]?.view?.name || "list") +
|
|
111
109
|
"Item"
|
|
112
110
|
).toString(),
|
|
113
111
|
),
|
|
114
112
|
)
|
|
115
|
-
const numberOfPages = computed(() => $stores[props.type].numberOfPages)
|
|
116
113
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
// Apollo: reactive query using variables computed from store
|
|
115
|
+
const variables = computed(() => {
|
|
116
|
+
console.log("computed variables loop")
|
|
117
|
+
return rootStore.buildListVariables(props.type, locale.value)
|
|
120
118
|
})
|
|
119
|
+
console.log("Starting query for type: ", props.type)
|
|
120
|
+
console.log("Using variables: ", variables.value)
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
137
|
-
}
|
|
138
|
-
// Fetch initial items
|
|
139
|
-
try {
|
|
140
|
-
await rootStore.update(props.type, locale.value)
|
|
141
|
-
} catch (e) {
|
|
142
|
-
console.error("Error fetching list:", e)
|
|
143
|
-
}
|
|
144
|
-
})
|
|
122
|
+
// Apollo GraphQL query with proper reactivity
|
|
123
|
+
const { data, pending, error, refresh } = await useAsyncQuery(
|
|
124
|
+
$queries[props.type]?.list,
|
|
125
|
+
variables, // Pass the reactive computed, not its value
|
|
126
|
+
{
|
|
127
|
+
key: `list-${props.type}`, // Unique key for caching
|
|
128
|
+
server: true, // Enable SSR
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
if (error.value) {
|
|
132
|
+
console.error("GraphQL query error: ", error.value)
|
|
133
|
+
} else {
|
|
134
|
+
console.log("Query result data: ", data.value.items?.length)
|
|
135
|
+
}
|
|
145
136
|
|
|
137
|
+
// Apply data to store immediately if available
|
|
138
|
+
if (data.value) {
|
|
139
|
+
console.log("Applying data to store directly [first load scenario]")
|
|
140
|
+
rootStore.applyListResult(props.type, data.value)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Watch for variable changes to refresh and apply new data
|
|
146
144
|
watch(
|
|
147
|
-
|
|
148
|
-
async (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
145
|
+
variables,
|
|
146
|
+
async (newVars, oldVars) => {
|
|
147
|
+
if (newVars && JSON.stringify(newVars) !== JSON.stringify(oldVars)) {
|
|
148
|
+
console.log("Variables changed, refreshing query, newVars: ", newVars)
|
|
149
|
+
console.log("start local loading from computed")
|
|
150
|
+
rootStore.setLoading(true, props.type)
|
|
151
|
+
await refresh()
|
|
152
|
+
if (data.value) {
|
|
153
|
+
console.log("Applying refreshed data to store")
|
|
154
|
+
rootStore.applyListResult(props.type, data.value)
|
|
155
|
+
}
|
|
156
|
+
rootStore.setLoading(false, props.type)
|
|
152
157
|
}
|
|
153
|
-
navigateTo({ query }, { replace: true })
|
|
154
|
-
await nextTick()
|
|
155
|
-
window.scrollTo({ top: 0, behavior: "smooth" })
|
|
156
158
|
},
|
|
159
|
+
{ deep: true },
|
|
157
160
|
)
|
|
161
|
+
|
|
162
|
+
// Reactive items computed from the store (single source of truth)
|
|
163
|
+
const items = computed(() => $stores[props.type]?.items || [])
|
|
164
|
+
|
|
165
|
+
onMounted(() => {
|
|
166
|
+
// On initial mount: clear loading state
|
|
167
|
+
console.log("STOP local loading from mounted")
|
|
168
|
+
rootStore.setLoading(false, props.type)
|
|
169
|
+
})
|
|
170
|
+
|
|
158
171
|
onBeforeUnmount(() => {
|
|
159
172
|
rootStore.resetState(props.type, locale.value)
|
|
160
173
|
})
|
|
161
174
|
|
|
162
175
|
async function onPageChange(newPage) {
|
|
163
|
-
|
|
176
|
+
console.log("onPageChange: ", newPage)
|
|
177
|
+
rootStore.updatePage({
|
|
164
178
|
page: newPage,
|
|
165
179
|
type: props.type,
|
|
166
180
|
lang: locale.value,
|
|
167
181
|
})
|
|
182
|
+
if (typeof window !== "undefined") {
|
|
183
|
+
window.scrollTo({ top: 0, behavior: "smooth" })
|
|
184
|
+
}
|
|
168
185
|
}
|
|
169
|
-
|
|
170
|
-
|
|
186
|
+
/*
|
|
187
|
+
onUpdated(() => {
|
|
188
|
+
console.log("STOP local loading from updated")
|
|
189
|
+
rootStore.setLoading(false, props.type)
|
|
190
|
+
}) */
|
|
171
191
|
</script>
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
2
|
+
<v-row
|
|
3
|
+
class="highlight-on-hover pa-3"
|
|
4
|
+
no-gutters
|
|
5
|
+
@click="$router.push(pathPrefix)"
|
|
6
|
+
>
|
|
7
|
+
<v-col cols="12" class="px-6">
|
|
8
|
+
<v-skeleton-loader v-if="isLoading" type="heading, text@8, button" />
|
|
9
|
+
<template v-else>
|
|
10
|
+
<div class="text-h5">{{ item.name }}</div>
|
|
11
|
+
<div v-if="item.summary" class="mt-2">
|
|
12
|
+
<MDC :value="item.summary" />
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
</v-col>
|
|
16
|
+
</v-row>
|
|
17
|
+
<v-divider />
|
|
3
18
|
</template>
|
|
4
19
|
|
|
5
20
|
<script setup>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
21
|
+
import { computed } from "#imports"
|
|
22
|
+
import { useRootStore } from "../../stores/root"
|
|
23
|
+
|
|
24
|
+
const rootStore = useRootStore()
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
item: { type: Object, required: true },
|
|
27
|
+
pathPrefix: { type: String, required: true },
|
|
28
|
+
loading: { type: Boolean, default: false },
|
|
15
29
|
})
|
|
30
|
+
|
|
31
|
+
const isLoading = computed(() => rootStore.loading || props.loading)
|
|
16
32
|
</script>
|
|
17
33
|
|
|
18
34
|
<style></style>
|