@paris-ias/list 1.0.179 → 1.0.181
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/events/DenseItem.vue +3 -2
- package/dist/runtime/components/fellowships/DenseItem.vue +6 -1
- package/dist/runtime/components/list/atoms/ResultsList.vue +5 -3
- package/dist/runtime/components/list/molecules/GlobalSearchInput.vue +49 -42
- package/dist/runtime/components/list/molecules/ResultsContainer.vue +26 -10
- package/dist/runtime/components/list/organisms/List.vue +1 -1
- package/dist/runtime/components/list/organisms/Results.vue +66 -64
- package/dist/runtime/components/list/views/Dense.vue +1 -1
- package/dist/runtime/components/misc/atoms/ImageContainer.vue +12 -12
- package/dist/runtime/components/news/DenseItem.vue +8 -5
- package/dist/runtime/components/news/RowsItem.vue +1 -1
- package/dist/runtime/components/people/DenseItem.vue +5 -3
- package/dist/runtime/components/projects/DenseItem.vue +5 -4
- package/dist/runtime/components/publications/DenseItem.vue +2 -1
- package/dist/runtime/stores/root.js +51 -12
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover
|
|
3
|
-
<v-col v-if="mdAndUp" cols="
|
|
2
|
+
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover py-2">
|
|
3
|
+
<v-col v-if="mdAndUp" cols="2">
|
|
4
4
|
<MiscAtomsDateStamp
|
|
5
5
|
v-if="item.start"
|
|
6
6
|
:loading
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
import { useI18n, useNuxtApp, computed } from "#imports"
|
|
92
92
|
import { useDisplay } from "vuetify"
|
|
93
93
|
import { useRootStore } from "../../stores/root"
|
|
94
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
94
95
|
const { $rootStore } = useNuxtApp()
|
|
95
96
|
const { smAndDown, mdAndUp } = useDisplay()
|
|
96
97
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-row
|
|
2
|
+
<v-row
|
|
3
|
+
v-ripple
|
|
4
|
+
no-gutters
|
|
5
|
+
class="cursor-pointer highlight-on-hover pt-2 pl-2"
|
|
6
|
+
>
|
|
3
7
|
<v-col align-self="center" cols="8" class="text-h5 dense">
|
|
4
8
|
<v-skeleton-loader
|
|
5
9
|
v-if="loading"
|
|
@@ -35,6 +39,7 @@
|
|
|
35
39
|
|
|
36
40
|
<script setup>
|
|
37
41
|
import { useNuxtApp } from "#imports"
|
|
42
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
38
43
|
const { $rootStore } = useNuxtApp()
|
|
39
44
|
|
|
40
45
|
const props = defineProps({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<component
|
|
3
3
|
:is="itemTemplate"
|
|
4
|
-
v-for="(item, index) in rootStore.results[type]
|
|
4
|
+
v-for="(item, index) in rootStore.results[type]?.items || []"
|
|
5
5
|
:key="index"
|
|
6
6
|
:item="item"
|
|
7
7
|
:index="index"
|
|
@@ -27,7 +27,9 @@ const itemTemplate = computed(() =>
|
|
|
27
27
|
capitalize(props.type) +
|
|
28
28
|
capitalize($stores[props.type].view.name) +
|
|
29
29
|
"Item"
|
|
30
|
-
).toString()
|
|
31
|
-
)
|
|
30
|
+
).toString(),
|
|
31
|
+
),
|
|
32
32
|
)
|
|
33
|
+
console.log("ResultsList props:", itemTemplate, $stores[props.type].view.name)
|
|
34
|
+
console
|
|
33
35
|
</script>
|
|
@@ -1,34 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="d-flex align-center">
|
|
3
|
-
<v-text-field
|
|
4
|
-
:id="`global-search-input-${type}`"
|
|
5
|
-
v-model.trim="search"
|
|
6
|
-
:placeholder="
|
|
7
|
-
type === 'all'
|
|
8
|
-
? t('search')
|
|
9
|
-
: $t('list.search-type', [$t('items.' + type, 2)])
|
|
10
|
-
"
|
|
11
|
-
prepend-inner-icon="mdi-magnify"
|
|
12
|
-
single-line
|
|
13
|
-
class="transition-swing flex-grow-1"
|
|
14
|
-
variant="outlined"
|
|
15
|
-
hide-details
|
|
16
|
-
clearable
|
|
17
|
-
tile
|
|
18
|
-
type="search"
|
|
19
|
-
:loading="rootStore.loading"
|
|
20
|
-
@keyup.enter="$router.push(localePath('/search'))"
|
|
21
|
-
@click:append="$router.push(localePath('/search'))"
|
|
22
|
-
>
|
|
23
|
-
<!-- :loading="$nuxt.loading || $store.state.loading" :class="{ 'mt-3':
|
|
24
|
-
$store.state.scrolled }" -->
|
|
25
|
-
<template v-if="!search" #label>
|
|
26
|
-
<div class="searchLabel">
|
|
27
|
-
{{ $t("search") }}
|
|
28
|
-
</div>
|
|
29
|
-
</template>
|
|
30
|
-
</v-text-field>
|
|
31
|
-
|
|
32
3
|
<v-menu
|
|
33
4
|
v-if="filter"
|
|
34
5
|
v-model="filterMenuOpen"
|
|
@@ -40,7 +11,7 @@
|
|
|
40
11
|
<v-btn
|
|
41
12
|
v-bind="menuProps"
|
|
42
13
|
:rounded="0"
|
|
43
|
-
variant="
|
|
14
|
+
variant="outlined"
|
|
44
15
|
size="large"
|
|
45
16
|
height="56"
|
|
46
17
|
>
|
|
@@ -73,13 +44,39 @@
|
|
|
73
44
|
</v-list>
|
|
74
45
|
</v-card>
|
|
75
46
|
</v-menu>
|
|
47
|
+
<v-text-field
|
|
48
|
+
:id="`global-search-input-${type}`"
|
|
49
|
+
v-model.trim="search"
|
|
50
|
+
:placeholder="
|
|
51
|
+
type === 'all'
|
|
52
|
+
? t('search')
|
|
53
|
+
: $t('list.search-type', [$t('items.' + type, 2)])
|
|
54
|
+
"
|
|
55
|
+
single-line
|
|
56
|
+
class="transition-swing flex-grow-1"
|
|
57
|
+
variant="outlined"
|
|
58
|
+
hide-details
|
|
59
|
+
clearable
|
|
60
|
+
tile
|
|
61
|
+
type="search"
|
|
62
|
+
:loading="rootStore.loading"
|
|
63
|
+
@keyup.enter="navigateToSearch"
|
|
64
|
+
@click:append="navigateToSearch"
|
|
65
|
+
>
|
|
66
|
+
<template v-if="!search" #label>
|
|
67
|
+
<div class="searchLabel">
|
|
68
|
+
{{ $t("search") }}
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
</v-text-field>
|
|
72
|
+
|
|
76
73
|
<v-btn
|
|
77
74
|
:rounded="0"
|
|
78
75
|
variant="outlined"
|
|
79
76
|
size="large"
|
|
80
77
|
height="56"
|
|
81
|
-
@keyup.enter="
|
|
82
|
-
@click="
|
|
78
|
+
@keyup.enter="navigateToSearch"
|
|
79
|
+
@click="navigateToSearch"
|
|
83
80
|
>
|
|
84
81
|
<v-icon size="large">mdi-magnify</v-icon>
|
|
85
82
|
<v-tooltip activator="parent" location="start">{{
|
|
@@ -92,7 +89,7 @@
|
|
|
92
89
|
<script setup>
|
|
93
90
|
import { useDebounceFn } from "@vueuse/core"
|
|
94
91
|
import { useRootStore } from "../../../stores/root"
|
|
95
|
-
import { computed, useI18n, ref, useLocalePath } from "#imports"
|
|
92
|
+
import { computed, useI18n, ref, useLocalePath, useRouter } from "#imports"
|
|
96
93
|
const localePath = useLocalePath()
|
|
97
94
|
const { locale, t } = useI18n()
|
|
98
95
|
const rootStore = useRootStore()
|
|
@@ -150,20 +147,30 @@ const toggleFilter = (option) => {
|
|
|
150
147
|
})
|
|
151
148
|
}
|
|
152
149
|
|
|
150
|
+
const navigateToSearch = () => {
|
|
151
|
+
navigateTo({
|
|
152
|
+
path: localePath("/search"),
|
|
153
|
+
query: rootStore.search ? { search: rootStore.search } : {},
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
153
157
|
const search = computed({
|
|
154
158
|
get() {
|
|
155
159
|
return rootStore.search
|
|
156
160
|
},
|
|
157
161
|
set: useDebounceFn(function (v) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
const value = v || ""
|
|
163
|
+
if (!value && !rootStore.search) return
|
|
164
|
+
|
|
165
|
+
if (props.type === "all") {
|
|
166
|
+
rootStore.search = value
|
|
167
|
+
} else {
|
|
168
|
+
rootStore.updateSearch({
|
|
169
|
+
type: props.type,
|
|
170
|
+
search: value,
|
|
171
|
+
lang: locale.value,
|
|
172
|
+
})
|
|
173
|
+
}
|
|
167
174
|
}, 300),
|
|
168
175
|
})
|
|
169
176
|
</script>
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
size="large"
|
|
7
7
|
class=""
|
|
8
8
|
@click="$emit('toggle', type)"
|
|
9
|
-
:disabled="
|
|
9
|
+
:disabled="
|
|
10
|
+
$rootStore.results[type] && $rootStore.results[type]?.total === 0
|
|
11
|
+
"
|
|
10
12
|
>
|
|
11
13
|
<v-icon size="large">{{
|
|
12
14
|
open ? "mdi-chevron-down" : "mdi-chevron-right"
|
|
@@ -19,7 +21,9 @@
|
|
|
19
21
|
<div
|
|
20
22
|
class="text-h5 font-weight-medium"
|
|
21
23
|
:class="
|
|
22
|
-
$rootStore.results[type].total > 0
|
|
24
|
+
$rootStore.results[type] && $rootStore.results[type].total > 0
|
|
25
|
+
? 'black'
|
|
26
|
+
: 'text-grey darken-2'
|
|
23
27
|
"
|
|
24
28
|
>
|
|
25
29
|
{{ capitalize($t("items." + props.type, 2)) }}
|
|
@@ -30,18 +34,26 @@
|
|
|
30
34
|
? $t(
|
|
31
35
|
"list.0-items-found-f",
|
|
32
36
|
[
|
|
33
|
-
$rootStore.results[type].total,
|
|
34
|
-
$t(
|
|
37
|
+
$rootStore.results[type] && $rootStore.results[type].total,
|
|
38
|
+
$t(
|
|
39
|
+
"items." + props.type,
|
|
40
|
+
$rootStore.results[type] &&
|
|
41
|
+
$rootStore.results[type].total,
|
|
42
|
+
),
|
|
35
43
|
],
|
|
36
|
-
$rootStore.results[type].total,
|
|
44
|
+
$rootStore.results[type] && $rootStore.results[type].total,
|
|
37
45
|
)
|
|
38
46
|
: $t(
|
|
39
47
|
"list.0-items-found",
|
|
40
48
|
[
|
|
41
|
-
$rootStore.results[type].total,
|
|
42
|
-
$t(
|
|
49
|
+
$rootStore.results[type] && $rootStore.results[type].total,
|
|
50
|
+
$t(
|
|
51
|
+
"items." + props.type,
|
|
52
|
+
$rootStore.results[type] &&
|
|
53
|
+
$rootStore.results[type].total,
|
|
54
|
+
),
|
|
43
55
|
],
|
|
44
|
-
$rootStore.results[type].total,
|
|
56
|
+
$rootStore.results[type] && $rootStore.results[type].total,
|
|
45
57
|
)
|
|
46
58
|
}}
|
|
47
59
|
</div>
|
|
@@ -54,10 +66,14 @@
|
|
|
54
66
|
color="default"
|
|
55
67
|
variant="text"
|
|
56
68
|
rounded="0"
|
|
57
|
-
v-if="$rootStore.results[type]?.total > 0"
|
|
69
|
+
v-if="$rootStore.results[type] && $rootStore.results[type]?.total > 0"
|
|
58
70
|
:to="localePath(type === 'people' ? '/people' : '/activities/' + type)"
|
|
59
71
|
>
|
|
60
|
-
{{
|
|
72
|
+
{{
|
|
73
|
+
$t("list.pls-x-more", [
|
|
74
|
+
$rootStore.results[type] && $rootStore.results[type].total,
|
|
75
|
+
])
|
|
76
|
+
}}
|
|
61
77
|
</v-btn>
|
|
62
78
|
</div>
|
|
63
79
|
<v-divider></v-divider>
|
|
@@ -147,7 +147,7 @@ const { data, pending, error, refresh } = await useAsyncQuery(
|
|
|
147
147
|
if (error.value) {
|
|
148
148
|
console.error("GraphQL query error: ", error.value)
|
|
149
149
|
} else {
|
|
150
|
-
console.log("Query result data: ", data.value)
|
|
150
|
+
/* console.log("Query result data: ", data.value) */
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// Apply data to store immediately if available
|
|
@@ -2,121 +2,123 @@
|
|
|
2
2
|
<ListMoleculesGlobalSearchInput
|
|
3
3
|
type="all"
|
|
4
4
|
:placeholder="$t('search')"
|
|
5
|
-
variant="outlined"
|
|
6
5
|
:categories="selectedCategories"
|
|
7
|
-
|
|
6
|
+
filter
|
|
8
7
|
@filter-change="handleFilterChange"
|
|
9
8
|
/>
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
<v-progress-linear v-if="pending" indeterminate />
|
|
10
|
+
<template v-else>
|
|
11
|
+
<ListMoleculesResultsContainer
|
|
12
|
+
v-for="type in filteredSortedModules"
|
|
13
|
+
:key="type"
|
|
14
|
+
:feminine="type === 'people'"
|
|
15
|
+
:type
|
|
16
|
+
:open="
|
|
17
|
+
($rootStore.results[type] && $rootStore.results[type]?.total > 0) ??
|
|
18
|
+
open[type]
|
|
19
|
+
"
|
|
20
|
+
@toggle="open[$event] = !open[$event]"
|
|
21
|
+
>
|
|
22
|
+
<v-expand-transition class="results-container">
|
|
23
|
+
<div
|
|
24
|
+
v-show="
|
|
25
|
+
($rootStore.results[type] && $rootStore.results[type]?.total > 0) ||
|
|
26
|
+
open[type]
|
|
27
|
+
"
|
|
28
|
+
>
|
|
29
|
+
<ListAtomsResultsList :type />
|
|
30
|
+
</div>
|
|
31
|
+
</v-expand-transition>
|
|
32
|
+
</ListMoleculesResultsContainer>
|
|
33
|
+
</template>
|
|
25
34
|
</template>
|
|
26
35
|
|
|
27
36
|
<script setup>
|
|
28
37
|
import {
|
|
29
38
|
useNuxtApp,
|
|
30
|
-
onBeforeUnmount,
|
|
31
39
|
useI18n,
|
|
32
40
|
useAppConfig,
|
|
41
|
+
useRoute,
|
|
33
42
|
ref,
|
|
34
43
|
useAsyncQuery,
|
|
35
44
|
computed,
|
|
45
|
+
watch,
|
|
36
46
|
} from "#imports"
|
|
37
47
|
import SEARCH from "@paris-ias/trees/dist/graphql/client/misc/query.search.all.gql"
|
|
38
|
-
// Component name for linting
|
|
39
|
-
defineOptions({
|
|
40
|
-
name: "SearchResults",
|
|
41
|
-
})
|
|
42
48
|
|
|
43
49
|
const { $rootStore } = useNuxtApp()
|
|
44
|
-
|
|
45
50
|
const appConfig = useAppConfig()
|
|
46
51
|
const { locale } = useI18n()
|
|
52
|
+
const route = useRoute()
|
|
47
53
|
const open = ref({})
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
if (route.query.search) {
|
|
56
|
+
$rootStore.search = route.query.search
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
const selectedCategories = ref([...appConfig.list.modules])
|
|
51
60
|
|
|
52
|
-
// Handle filter changes
|
|
53
61
|
const handleFilterChange = (filterData) => {
|
|
54
62
|
selectedCategories.value = filterData.categories
|
|
55
63
|
}
|
|
56
64
|
|
|
57
|
-
// Computed property to sort modules by total count (highest first)
|
|
58
65
|
const sortedModules = computed(() => {
|
|
59
66
|
return appConfig.list.modules.slice().sort((a, b) => {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
const aMaxScore = Math.max(
|
|
68
|
+
...($rootStore.results[a]?.items || []).map((i) => i.score ?? 0),
|
|
69
|
+
0,
|
|
70
|
+
)
|
|
71
|
+
const bMaxScore = Math.max(
|
|
72
|
+
...($rootStore.results[b]?.items || []).map((i) => i.score ?? 0),
|
|
73
|
+
0,
|
|
74
|
+
)
|
|
75
|
+
return bMaxScore - aMaxScore
|
|
65
76
|
})
|
|
66
77
|
})
|
|
67
|
-
|
|
68
|
-
// Computed property to filter and sort modules based on selected categories
|
|
69
78
|
const filteredSortedModules = computed(() => {
|
|
70
79
|
return sortedModules.value.filter((type) =>
|
|
71
80
|
selectedCategories.value.includes(type),
|
|
72
81
|
)
|
|
73
82
|
})
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
const
|
|
84
|
+
const searchTerm = computed(() => $rootStore.search || "")
|
|
85
|
+
const currentLocale = computed(() => locale.value)
|
|
86
|
+
|
|
87
|
+
const { data, pending, error } = useAsyncQuery(
|
|
77
88
|
SEARCH,
|
|
78
|
-
|
|
89
|
+
computed(() => ({
|
|
90
|
+
search: searchTerm.value,
|
|
91
|
+
appId: "iea",
|
|
92
|
+
locale: currentLocale.value,
|
|
93
|
+
})),
|
|
79
94
|
{
|
|
80
|
-
|
|
81
|
-
server: true, // Enable SSR
|
|
95
|
+
enabled: computed(() => searchTerm.value.length > 0),
|
|
82
96
|
},
|
|
83
97
|
)
|
|
84
98
|
if (error.value) {
|
|
85
99
|
console.error("GraphQL query error: ", error.value)
|
|
86
100
|
} else {
|
|
87
|
-
console.log("Query result data: ", data.value.items?.length)
|
|
101
|
+
/* console.log("Query result data: ", data.value.items?.length) */
|
|
88
102
|
}
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if ($rootStore.results[type]?.total > 0) {
|
|
97
|
-
open.value[type] = true
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const updateSearch = async (newSearch) => {
|
|
103
|
-
console.log("update search")
|
|
104
|
-
if (newSearch !== $rootStore.search) {
|
|
105
|
-
await refresh()
|
|
106
|
-
if (data.value) {
|
|
107
|
-
console.log("Applying data to store directly [first load scenario]")
|
|
108
|
-
$rootStore.applyListResult("all", data.value)
|
|
109
|
-
// Initialize open state for types with results
|
|
104
|
+
watch(
|
|
105
|
+
data,
|
|
106
|
+
(newData) => {
|
|
107
|
+
if (newData) {
|
|
108
|
+
console.log("Applying search data to store")
|
|
109
|
+
$rootStore.applyListResult("all", newData)
|
|
110
110
|
appConfig.list.modules.forEach((type) => {
|
|
111
|
-
if ($rootStore.results[type]?.total > 0) {
|
|
111
|
+
if ($rootStore.results[type] && $rootStore.results[type]?.total > 0) {
|
|
112
112
|
open.value[type] = true
|
|
113
113
|
}
|
|
114
114
|
})
|
|
115
115
|
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
},
|
|
117
|
+
{ immediate: true },
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
watch(error, (err) => {
|
|
121
|
+
if (err) console.error("GraphQL query error:", err)
|
|
120
122
|
})
|
|
121
123
|
</script>
|
|
122
124
|
<style scoped>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<div class="overflow-hidden mw-100">
|
|
12
12
|
<!-- TODO debug why the picture is not displaying/sizing properly -->
|
|
13
13
|
<v-img
|
|
14
|
-
v-if="src"
|
|
14
|
+
v-if="src && computedSrc"
|
|
15
15
|
:aspect-ratio="ratio"
|
|
16
16
|
:class="{ 'img-animation': animate }"
|
|
17
17
|
:lazy-src="
|
|
@@ -43,7 +43,8 @@ import { computed, useImage } from "#imports"
|
|
|
43
43
|
const img = useImage()
|
|
44
44
|
|
|
45
45
|
const computedSrc = computed(() => {
|
|
46
|
-
|
|
46
|
+
if (!props.src) return null
|
|
47
|
+
return typeof props.src === "string" ? props.src : props.src?.url || null
|
|
47
48
|
})
|
|
48
49
|
const props = defineProps({
|
|
49
50
|
src: {
|
|
@@ -68,17 +69,16 @@ const props = defineProps({
|
|
|
68
69
|
animate: { type: Boolean, default: true },
|
|
69
70
|
})
|
|
70
71
|
const _srcset = computed(() => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
},
|
|
72
|
+
const srcUrl = typeof props.src === "string" ? props.src : props.src?.url
|
|
73
|
+
if (!srcUrl) return { srcset: "", sizes: "" }
|
|
74
|
+
return img.getSizes(srcUrl, {
|
|
75
|
+
sizes: "xs:100vw sm:100vw md:100vw lg:100vw xl:100vw",
|
|
76
|
+
modifiers: {
|
|
77
|
+
format: "webp",
|
|
78
|
+
quality: 70,
|
|
79
|
+
...(props.width && { width: props.width }),
|
|
80
80
|
},
|
|
81
|
-
)
|
|
81
|
+
})
|
|
82
82
|
})
|
|
83
83
|
</script>
|
|
84
84
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover
|
|
2
|
+
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover pa-2">
|
|
3
3
|
<v-col v-if="mdAndUp" align-self="center" cols="1">
|
|
4
4
|
<MiscAtomsImageContainer
|
|
5
5
|
cover
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
width="80px"
|
|
12
12
|
/>
|
|
13
13
|
</v-col>
|
|
14
|
-
<v-col align-self="start" class="text-h5 dense
|
|
14
|
+
<v-col align-self="start" class="text-h5 dense mx-2 paragraph">
|
|
15
15
|
<v-skeleton-loader v-if="loading" type="heading" />
|
|
16
16
|
<template v-else>
|
|
17
17
|
<v-skeleton-loader
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<template v-else>
|
|
27
27
|
<v-chip
|
|
28
|
-
class="
|
|
28
|
+
class="mb-2"
|
|
29
29
|
style="background-color: white; color: black"
|
|
30
30
|
size="small"
|
|
31
31
|
variant="outlined"
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
<div
|
|
38
38
|
v-html="
|
|
39
|
-
|
|
39
|
+
rootStore.search.length
|
|
40
40
|
? highlightAndTruncate(
|
|
41
41
|
300,
|
|
42
42
|
item.name,
|
|
43
|
-
|
|
43
|
+
rootStore.search.split(' '),
|
|
44
44
|
)
|
|
45
45
|
: item.name
|
|
46
46
|
"
|
|
@@ -52,9 +52,12 @@
|
|
|
52
52
|
|
|
53
53
|
<script setup>
|
|
54
54
|
import { useDisplay } from "vuetify"
|
|
55
|
+
import { useRootStore } from "../../stores/root"
|
|
56
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
55
57
|
import { computed } from "#imports"
|
|
56
58
|
|
|
57
59
|
const { name, mdAndUp } = useDisplay()
|
|
60
|
+
const rootStore = useRootStore()
|
|
58
61
|
|
|
59
62
|
const props = defineProps({
|
|
60
63
|
item: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover
|
|
2
|
+
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover">
|
|
3
3
|
<v-col v-if="mdAndUp" cols="1">
|
|
4
4
|
<MiscAtomsImageContainer
|
|
5
5
|
cover
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"
|
|
10
10
|
:ratio="1 / 1"
|
|
11
11
|
:width="80"
|
|
12
|
+
class="ma-1"
|
|
12
13
|
/>
|
|
13
14
|
</v-col>
|
|
14
15
|
<v-col align-self="start" class="text-h6 dense px-2">
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
? highlightAndTruncate(
|
|
21
22
|
300,
|
|
22
23
|
item.firstname + ' ' + item.lastname,
|
|
23
|
-
|
|
24
|
+
rootStore.search.split(' '),
|
|
24
25
|
)
|
|
25
26
|
: item.firstname + ' ' + item.lastname
|
|
26
27
|
"
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
? highlightAndTruncate(
|
|
37
38
|
300,
|
|
38
39
|
item.groups.vintage[0].theme,
|
|
39
|
-
|
|
40
|
+
rootStore.search.split(' '),
|
|
40
41
|
)
|
|
41
42
|
: item.groups.vintage[0].theme
|
|
42
43
|
"
|
|
@@ -47,6 +48,7 @@
|
|
|
47
48
|
|
|
48
49
|
<script setup>
|
|
49
50
|
import { useRootStore } from "../../stores/root"
|
|
51
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
50
52
|
import { computed } from "#imports"
|
|
51
53
|
import { useDisplay } from "vuetify"
|
|
52
54
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover">
|
|
2
|
+
<v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover px-4">
|
|
3
3
|
<v-col v-if="mdAndUp" align-self="center" cols="1">
|
|
4
4
|
<MiscAtomsImageContainer
|
|
5
5
|
cover
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
:width="50"
|
|
12
12
|
/>
|
|
13
13
|
</v-col>
|
|
14
|
-
<v-col align-self="center" class="text-h5 dense pl-2">
|
|
14
|
+
<v-col align-self="center" class="text-h5 dense pl-4 pt-2">
|
|
15
15
|
<v-skeleton-loader v-if="loading" type="heading" width="50%" />
|
|
16
16
|
<span
|
|
17
17
|
v-else
|
|
18
18
|
v-html="
|
|
19
19
|
rootStore.search.length
|
|
20
|
-
? highlightAndTruncate(300, item.name,
|
|
20
|
+
? highlightAndTruncate(300, item.name, rootStore.search.split(' '))
|
|
21
21
|
: item.name
|
|
22
22
|
"
|
|
23
23
|
/>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
<MDC
|
|
34
34
|
v-else-if="item.summary"
|
|
35
|
-
class="text-caption font-weight-light paragraph"
|
|
35
|
+
class="text-caption font-weight-light paragraph mt-n2"
|
|
36
36
|
:value="`${highlightAndTruncate(
|
|
37
37
|
150,
|
|
38
38
|
item.summary,
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
<script setup>
|
|
47
47
|
import { useDisplay } from "vuetify"
|
|
48
48
|
import { useRootStore } from "../../stores/root"
|
|
49
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
49
50
|
|
|
50
51
|
const { mdAndUp } = useDisplay()
|
|
51
52
|
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
? highlightAndTruncate(
|
|
49
49
|
300,
|
|
50
50
|
item.name,
|
|
51
|
-
|
|
51
|
+
rootStore.search.split(' '),
|
|
52
52
|
)
|
|
53
53
|
: item.name
|
|
54
54
|
"
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
<script setup>
|
|
72
72
|
import { useDisplay } from "vuetify"
|
|
73
73
|
import { useRootStore } from "../../stores/root"
|
|
74
|
+
import { highlightAndTruncate } from "../../composables/useUtils"
|
|
74
75
|
import { computed } from "#imports"
|
|
75
76
|
const rootStore = useRootStore()
|
|
76
77
|
|
|
@@ -54,8 +54,20 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
|
-
if (query.
|
|
58
|
-
|
|
57
|
+
if (query.search && typeof query.search === "string") {
|
|
58
|
+
if (type === "all") {
|
|
59
|
+
this.search = query.search;
|
|
60
|
+
} else if ($stores[type]) {
|
|
61
|
+
;
|
|
62
|
+
$stores[type].search = query.search;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const page = parseInt(query.page, 10) || 1;
|
|
66
|
+
if (type === "all") {
|
|
67
|
+
this.page = page;
|
|
68
|
+
} else if ($stores[type]) {
|
|
69
|
+
$stores[type].page = page;
|
|
70
|
+
}
|
|
59
71
|
},
|
|
60
72
|
setFiltersCount(type) {
|
|
61
73
|
const { $stores } = useNuxtApp();
|
|
@@ -70,9 +82,12 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
70
82
|
updateRouteQuery(type) {
|
|
71
83
|
const router = useRouter();
|
|
72
84
|
const { $stores } = useNuxtApp();
|
|
85
|
+
const isGlobal = type === "all";
|
|
86
|
+
const searchValue = isGlobal ? this.search : $stores[type]?.search || "";
|
|
87
|
+
const pageValue = isGlobal ? this.page : $stores[type]?.page || 1;
|
|
73
88
|
const routeQuery = {
|
|
74
|
-
...
|
|
75
|
-
...
|
|
89
|
+
...searchValue ? { search: searchValue } : {},
|
|
90
|
+
...pageValue > 1 ? { page: pageValue.toString() } : {},
|
|
76
91
|
...Object.entries($stores[type]?.filters ?? {}).reduce(
|
|
77
92
|
(acc, [key, filter]) => {
|
|
78
93
|
const value = filter?.value;
|
|
@@ -125,7 +140,11 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
125
140
|
if ($stores[type]?.filters?.[key]) {
|
|
126
141
|
$stores[type].filters[key].value = val;
|
|
127
142
|
}
|
|
128
|
-
|
|
143
|
+
if (type === "all") {
|
|
144
|
+
this.page = 1;
|
|
145
|
+
} else {
|
|
146
|
+
$stores[type].page = 1;
|
|
147
|
+
}
|
|
129
148
|
$stores[type].loading = true;
|
|
130
149
|
this.setFiltersCount(type);
|
|
131
150
|
this.updateRouteQuery(type);
|
|
@@ -136,7 +155,11 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
136
155
|
lang
|
|
137
156
|
}) {
|
|
138
157
|
const { $stores } = useNuxtApp();
|
|
139
|
-
|
|
158
|
+
if (type === "all") {
|
|
159
|
+
this.page = 1;
|
|
160
|
+
} else {
|
|
161
|
+
$stores[type].page = 1;
|
|
162
|
+
}
|
|
140
163
|
$stores[type].itemsPerPage = value;
|
|
141
164
|
$stores[type].loading = true;
|
|
142
165
|
this.updateRouteQuery(type);
|
|
@@ -170,15 +193,16 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
170
193
|
}) {
|
|
171
194
|
if (type === "all") {
|
|
172
195
|
this.search = search;
|
|
196
|
+
this.page = 1;
|
|
173
197
|
} else {
|
|
174
198
|
const { $stores } = useNuxtApp();
|
|
175
199
|
if ($stores[type]) {
|
|
176
200
|
;
|
|
177
201
|
$stores[type].search = search;
|
|
202
|
+
$stores[type].page = 1;
|
|
178
203
|
$stores[type].loading = true;
|
|
179
204
|
}
|
|
180
205
|
}
|
|
181
|
-
this.page = 1;
|
|
182
206
|
this.updateRouteQuery(type);
|
|
183
207
|
},
|
|
184
208
|
buildListVariables(type, lang = "en") {
|
|
@@ -194,21 +218,20 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
194
218
|
}
|
|
195
219
|
}
|
|
196
220
|
}
|
|
221
|
+
const localSearch = $stores[type]?.search || "";
|
|
197
222
|
const args = JSON.parse(
|
|
198
223
|
JSON.stringify({
|
|
199
224
|
options: {
|
|
200
225
|
skip: +$stores[type]?.page === 1 ? 0 : (+$stores[type]?.page - 1) * itemsPerPage,
|
|
201
226
|
limit: itemsPerPage,
|
|
202
|
-
...
|
|
227
|
+
...type !== "all" && localSearch?.length && { search: localSearch },
|
|
203
228
|
filters,
|
|
204
229
|
sort: $stores[type]?.sortKey || ($stores[type]?.sort ? Object.keys($stores[type].sort).find(
|
|
205
230
|
(key) => $stores[type].sort[key].default
|
|
206
231
|
) : void 0)
|
|
207
232
|
},
|
|
208
233
|
...type === "all" && this.search?.length && { search: this.search },
|
|
209
|
-
...type !== "all" &&
|
|
210
|
-
search: $stores[type].search
|
|
211
|
-
},
|
|
234
|
+
...type !== "all" && localSearch?.length && { search: localSearch },
|
|
212
235
|
appId: "iea",
|
|
213
236
|
lang
|
|
214
237
|
})
|
|
@@ -220,7 +243,23 @@ export const useRootStore = defineStore("rootStore", {
|
|
|
220
243
|
const { $stores } = useNuxtApp();
|
|
221
244
|
const key = type === "all" ? "search" : "list" + type.charAt(0).toUpperCase() + type.slice(1);
|
|
222
245
|
if (type === "all") {
|
|
223
|
-
|
|
246
|
+
const searchData = data?.[key];
|
|
247
|
+
if (searchData) {
|
|
248
|
+
for (const moduleType of Object.keys(searchData)) {
|
|
249
|
+
if (moduleType in this.results) {
|
|
250
|
+
;
|
|
251
|
+
this.results[moduleType] = searchData[moduleType];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
for (const category of Object.keys(this.results)) {
|
|
256
|
+
const categoryData = this.results[category];
|
|
257
|
+
if (categoryData?.items?.length) {
|
|
258
|
+
categoryData.items.sort(
|
|
259
|
+
(a, b) => (b.score ?? 0) - (a.score ?? 0)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
224
263
|
return;
|
|
225
264
|
}
|
|
226
265
|
const items = data?.[key]?.items ?? [];
|