@paris-ias/list 1.0.180 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@paris-ias/list",
3
3
  "configKey": "list",
4
- "version": "1.0.180",
4
+ "version": "1.0.181",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
@@ -1,6 +1,6 @@
1
1
  <template>
2
- <v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover my-2">
3
- <v-col v-if="mdAndUp" cols="1">
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
@@ -1,5 +1,9 @@
1
1
  <template>
2
- <v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover">
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"
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <component
3
3
  :is="itemTemplate"
4
- v-for="(item, index) in rootStore.results[type].items"
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="text"
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="$router.push(localePath('/search'))"
82
- @click="$router.push(localePath('/search'))"
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
- emit("change", {
159
- name: "search",
160
- value: v,
161
- })
162
- rootStore.updateSearch({
163
- type: props.type,
164
- search: v || "",
165
- lang: locale.value,
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="$rootStore.results[type]?.total === 0"
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 ? 'black' : 'text-grey darken-2'
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("items." + props.type, $rootStore.results[type].total),
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("items." + props.type, $rootStore.results[type].total),
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
- {{ $t("list.pls-x-more", [$rootStore.results[type].total]) }}
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>
@@ -2,83 +2,97 @@
2
2
  <ListMoleculesGlobalSearchInput
3
3
  type="all"
4
4
  :placeholder="$t('search')"
5
- variant="outlined"
6
5
  :categories="selectedCategories"
7
- @change="updateSearch($event)"
6
+ filter
8
7
  @filter-change="handleFilterChange"
9
8
  />
10
- <ListMoleculesResultsContainer
11
- v-for="type in filteredSortedModules"
12
- :key="type"
13
- :feminine="type === 'people'"
14
- :type
15
- :open="$rootStore.results[type]?.total > 0 ?? open[type]"
16
- @toggle="open[$event] = !open[$event]"
17
- >
18
- {{ $rootStore.results[type]?.total }}
19
- <v-expand-transition class="results-container">
20
- <div v-show="$rootStore.results[type]?.total > 0 || open[type]">
21
- <ListAtomsResultsList :type />
22
- </div>
23
- </v-expand-transition>
24
- </ListMoleculesResultsContainer>
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
- // State for selected categories (default to all selected)
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 aResults = $rootStore.results[a] || { total: 0 }
61
- const bResults = $rootStore.results[b] || { total: 0 }
62
-
63
- // Sort by highest total count first
64
- return (bResults.total || 0) - (aResults.total || 0)
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
- // Apollo GraphQL query with proper reactivity
76
- const { data, pending, error, refresh } = await useAsyncQuery(
84
+ const searchTerm = computed(() => $rootStore.search || "")
85
+ const currentLocale = computed(() => locale.value)
86
+
87
+ const { data, pending, error } = useAsyncQuery(
77
88
  SEARCH,
78
- { search: $rootStore.search, appId: "iea", locale: locale.value },
89
+ computed(() => ({
90
+ search: searchTerm.value,
91
+ appId: "iea",
92
+ locale: currentLocale.value,
93
+ })),
79
94
  {
80
- key: `search-${$rootStore.search}`, // Unique key for caching
81
- server: true, // Enable SSR
95
+ enabled: computed(() => searchTerm.value.length > 0),
82
96
  },
83
97
  )
84
98
  if (error.value) {
@@ -87,93 +101,25 @@ if (error.value) {
87
101
  /* console.log("Query result data: ", data.value.items?.length) */
88
102
  }
89
103
 
90
- // Apply data to store immediately if available
91
- if (data.value) {
92
- console.log("Applying data to store directly [first load scenario]")
93
- $rootStore.applyListResult("all", data.value)
94
- // Initialize open state for types with results
95
- appConfig.list.modules.forEach((type) => {
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
- onBeforeUnmount(() => {
119
- /* rootStore.resetState("all", locale.value) */
120
- })
121
-
122
- const socioscope = {
123
- appId: ["iea"],
124
- url: "https://thesocioscope.org",
125
- subtitle: {
126
- en: "Seeing How Social Change Takes Shape",
127
- fr: "Voir comment le changement social prend forme",
128
- },
129
- date: {
130
- $date: "2023-03-18T00:00:00.000Z",
131
- },
132
- image: {
133
- url: "https://cdn-yggdrasil-dev.s3.eu-west-2.amazonaws.com/iea/project/the_socioscope.svg",
134
- },
135
- summary: {
136
- en: "Through large scale data collection around the world and LLM-driven research, the Socioscope analyses how behaviours, norms, and practices evolve within sustainable food transitions.\nWe're building a systemic way to help make complex social patterns measurable, comparable, and understandable.",
137
- fr: "Grâce à la collecte de données à grande échelle dans le monde entier et à la recherche pilotée par LLM, le Socioscope analyse comment les comportements, normes et pratiques évoluent dans les transitions alimentaires durables.\nNous construisons une méthode systématique pour rendre les schémas sociaux complexes mesurables, comparables et compréhensibles.",
138
- },
139
- description: {
140
- en: "The Socioscope is a transformative qualitative research project that maps how behaviours, norms, and communities influence the transition toward sustainable food systems.\nThe Socioscope serves as a comprehensive observatory of these efforts, making knowledge accessible to researchers, policymakers, and practitioners worldwide. Equally important is shining a light on local initiatives that lead change on the ground and drive the shift toward a more sustainable food system.",
141
- fr: "Le Socioscope est un projet de recherche qualitative transformatif qui cartographie comment les comportements, normes et communautés influencent la transition vers des systèmes alimentaires durables.\nLe Socioscope sert d'observatoire complet de ces efforts, rendant les connaissances accessibles aux chercheurs, décideurs politiques et praticiens du monde entier. Tout aussi important, il met en lumière les initiatives locales qui mènent le changement sur le terrain et conduisent la transition vers un système alimentaire plus durable.",
142
- },
143
- name: {
144
- en: "The Socioscope",
145
- fr: "Le Socioscope",
146
116
  },
147
- related: {
148
- people: [
149
- {
150
- firstname: "Antoine",
151
- lastname: "Cordelois",
152
- image: {
153
- url: "https://cdn-yggdrasil-dev.s3.eu-west-2.amazonaws.com/iea/people/antoine_cordelois.jpg",
154
- },
155
- },
156
- {
157
- firstname: "Saadi",
158
- lastname: "Lahlou",
159
- image: {
160
- url: "https://cdn-yggdrasil-dev.s3.eu-west-2.amazonaws.com/iea/people/lahlou_saadi.jpg",
161
- },
162
- },
163
- {
164
- firstname: "Paulius",
165
- lastname: "Yamin",
166
- image: {
167
- url: "https://cdn-yggdrasil-dev.s3.eu-west-2.amazonaws.com/iea/people/Paulius_Yamin.jpg",
168
- },
169
- },
170
- ],
171
- },
172
- slug: {
173
- fr: "le-socioscope",
174
- en: "the-socioscope",
175
- },
176
- }
117
+ { immediate: true },
118
+ )
119
+
120
+ watch(error, (err) => {
121
+ if (err) console.error("GraphQL query error:", err)
122
+ })
177
123
  </script>
178
124
  <style scoped>
179
125
  .results-container{display:flex;flex-direction:column;gap:8px;margin-left:8px}
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <section class="my-6 ml-2 pb-6">
2
+ <section class="my-6 pb-6">
3
3
  <slot>
4
4
  <!-- fallback content -->
5
5
  </slot>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover my-2">
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 px-2 paragraph">
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="ma-2"
28
+ class="mb-2"
29
29
  style="background-color: white; color: black"
30
30
  size="small"
31
31
  variant="outlined"
@@ -68,7 +68,7 @@
68
68
  </v-col>
69
69
 
70
70
  <v-col v-if="lgAndUp" cols="12" lg="5">
71
- <v-skeleton-loader v-if="isLoading" type="text@8, ossein, button" />
71
+ <v-skeleton-loader v-if="loading" type="text@8, ossein, button" />
72
72
 
73
73
  <template v-else>
74
74
  <div
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-row v-ripple no-gutters class="cursor-pointer highlight-on-hover my-2">
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">
@@ -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,7 +11,7 @@
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
@@ -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,
@@ -54,8 +54,20 @@ export const useRootStore = defineStore("rootStore", {
54
54
  }
55
55
  });
56
56
  }
57
- if (query.page && query.page > 1)
58
- $stores[type].page = parseInt(query.page, 10) || 1;
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
- ...this.search ? { search: this.search } : {},
75
- ...this.page > 1 ? { page: this.page.toString() } : {},
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
- this.page = 1;
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
- this.page = 1;
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
- ...this.search?.length && type !== "all" && { search: this.search },
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" && $stores[type] && $stores[type].search?.length && {
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
- this.results = data?.[key] || this.results;
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 ?? [];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "license": "AGPL-3.0-only",
3
3
  "main": "./dist/module.mjs",
4
- "version": "1.0.180",
4
+ "version": "1.0.181",
5
5
  "name": "@paris-ias/list",
6
6
  "repository": {
7
7
  "url": "git+https://github.com/IEA-Paris/list.git",