@paris-ias/list 1.0.85 → 1.0.87

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.85",
4
+ "version": "1.0.87",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.0",
7
7
  "unbuild": "3.5.0"
@@ -17,7 +17,11 @@
17
17
  $store.state.scrolled }" -->
18
18
  <template v-if="!search" #label>
19
19
  <div class="searchLabel">
20
- {{ $t("list.search-type", [$t("items." + type, 2)]) }}
20
+ {{
21
+ type === "all"
22
+ ? $t("search")
23
+ : $t("list.search-type", [$t("items." + type, 2)])
24
+ }}
21
25
  </div>
22
26
  </template>
23
27
  </v-text-field>
@@ -37,7 +41,7 @@
37
41
  v-if="item.type && item.type === 'subheader'"
38
42
  :key="'subheader-' + index"
39
43
  >
40
- {{ item.name }}
44
+ {{ $t(item.name) }}
41
45
  </v-list-subheader>
42
46
  <div
43
47
  v-else-if="item.type && item.type === 'no-result'"
@@ -1,6 +1,10 @@
1
1
  <template>
2
- <v-list-item :to="localePath(getPath(item.id))" class="search-item py-2">
3
- <template #item :key="index.toString() + item.id" />
2
+ <v-list-item
3
+ :key="index.toString() + item.id"
4
+ :to="localePath(getPath(item.id))"
5
+ class="search-item py-2"
6
+ >
7
+ <template #item />
4
8
  <template v-if="item.prependAvatar" #prepend>
5
9
  <v-avatar rounded="0" :image="item.prependAvatar" />
6
10
  </template>
@@ -14,7 +18,7 @@
14
18
  <v-btn
15
19
  icon="mdi-open-in-new"
16
20
  variant="text"
17
- :to="localePath(getPath(item.id))"
21
+ :to="localePath(getPath(item.slug || item.id))"
18
22
  target="_blank"
19
23
  />
20
24
  </template>
@@ -24,9 +24,11 @@
24
24
 
25
25
  <script setup>
26
26
  import { ref, computed } from "vue";
27
+ import { useNuxtApp } from "#imports";
28
+ const { $stores } = useNuxtApp();
27
29
  const filtersOpen = ref(false);
28
30
  const visible = computed(() => {
29
- return $stores[type]?.filtersCount && $stores[type]?.filtersCount > 0;
31
+ return $stores[props.type]?.filtersCount && $stores[props.type]?.filtersCount > 0;
30
32
  });
31
33
  const props = defineProps({
32
34
  type: {
@@ -2,14 +2,14 @@
2
2
  <v-row no-gutters>
3
3
  <v-col>
4
4
  <template v-for="(value, key, index) in socials" :key="key + value">
5
- <v-tooltip :location="location" v-if="value">
6
- <template v-slot:activator="{ props }">
5
+ <v-tooltip v-if="value" :location="location">
6
+ <template #activator="{ props }">
7
7
  <v-btn
8
8
  tile
9
9
  v-bind="mergeProps(props, attrs)"
10
10
  target="_blank"
11
11
  :href="getSocialId(key, value)"
12
- :color="dark ? 'black' : 'white'"
12
+ :color="dark ? 'transparent' : 'white'"
13
13
  flat
14
14
  >
15
15
  <v-icon :color="dark ? 'white' : 'black'">
@@ -29,10 +29,9 @@
29
29
  </template>
30
30
 
31
31
  <script setup>
32
- import { useAttrs } from "vue";
33
- import { mergeProps } from "vue";
34
- const attrs = useAttrs();
32
+ import { useAttrs, mergeProps } from "vue";
35
33
  import { useDisplay } from "vuetify";
34
+ const attrs = useAttrs();
36
35
  const { name } = useDisplay();
37
36
  const props = defineProps({
38
37
  socials: {
@@ -53,11 +53,15 @@
53
53
  <MiscAtomsSocials v-if="item.socials" :socials="item.socials" />
54
54
  <PeopleGroupBadges :item="item" />
55
55
  <div
56
- v-if="item.biography"
56
+ v-if="item.summary && item.summary.length > 0"
57
57
  class="text-wrap clamped-text text-black"
58
58
  :style="'-webkit-line-clamp:' + lineClamp"
59
59
  >
60
- <MDC :value="item.biography" />
60
+ <MDC :value="item.summary" />
61
+ </div>
62
+
63
+ <div v-else class="text-body-2">
64
+ {{ $t("no-biography") }}
61
65
  </div>
62
66
  </div>
63
67
  </v-col>
@@ -84,7 +84,13 @@
84
84
  "
85
85
  />
86
86
  <template v-else class="my-6 flex-wrap">
87
- <MDC v-if="item.biography" :value="item.biography" />
87
+ <MDC
88
+ v-if="item.biography && item.biography.length > 0"
89
+ :value="item.biography"
90
+ />
91
+ <div v-else class="text-body-2">
92
+ {{ $t("no-biography") }}
93
+ </div>
88
94
  </template>
89
95
 
90
96
  <!-- DIVIDERS -->
@@ -9,6 +9,7 @@ query listPeople(
9
9
  slug
10
10
  biography
11
11
  firstname
12
+ summary
12
13
  groups {
13
14
  board
14
15
  fellows
@@ -1,4 +1,28 @@
1
- export declare const useRootStore: import("pinia").StoreDefinition<"rootStore", Record<string, any>, {}, {
1
+ interface SearchResults {
2
+ events: Record<string, unknown>;
3
+ news: Record<string, unknown>;
4
+ people: Record<string, unknown>;
5
+ projects: Record<string, unknown>;
6
+ fellowships: Record<string, unknown>;
7
+ publications: Record<string, unknown>;
8
+ actions: Record<string, unknown>;
9
+ affiliations: Record<string, unknown>;
10
+ disciplines: Record<string, unknown>;
11
+ files: Record<string, unknown>;
12
+ mailing: Record<string, unknown>;
13
+ tags: Record<string, unknown>;
14
+ }
15
+ interface RootStoreState {
16
+ scrolled: boolean;
17
+ loading: boolean;
18
+ total: number;
19
+ skip: number;
20
+ page: number;
21
+ numberOfPages: number;
22
+ search: string;
23
+ results: SearchResults;
24
+ }
25
+ export declare const useRootStore: import("pinia").StoreDefinition<"rootStore", RootStoreState, {}, {
2
26
  setLoading(value: boolean, type?: string): void;
3
27
  setScrolled(): void;
4
28
  saveFiltersToLocalStorage(type: string): void;
@@ -7,8 +31,8 @@ export declare const useRootStore: import("pinia").StoreDefinition<"rootStore",
7
31
  setFiltersCount(type: string): void;
8
32
  updateRouteQuery(type: string): void;
9
33
  resetState(type: string): void;
10
- updateSort({ value, type }: {
11
- value: number[] | string[];
34
+ updateSort({ value, type, }: {
35
+ value: (number | string)[];
12
36
  type: string;
13
37
  }): void;
14
38
  updateView({ value, type }: {
@@ -16,7 +40,7 @@ export declare const useRootStore: import("pinia").StoreDefinition<"rootStore",
16
40
  type: string;
17
41
  }): void;
18
42
  updateLocalStorage(key: string, value: string): void;
19
- updateFilter(key: string, val: any, type: string): void;
43
+ updateFilter(key: string, val: unknown, type: string): void;
20
44
  updateItemsPerPage({ value, type }: {
21
45
  value: number;
22
46
  type: string;
@@ -32,3 +56,4 @@ export declare const useRootStore: import("pinia").StoreDefinition<"rootStore",
32
56
  }): Promise<void>;
33
57
  update(type: string, lang?: string): Promise<boolean>;
34
58
  }>;
59
+ export {};
@@ -3,7 +3,7 @@ import SEARCH from "../graphql/list/search.gql";
3
3
  import { useNuxtApp, useRouter, useAsyncQuery } from "#imports";
4
4
  export const useRootStore = defineStore("rootStore", {
5
5
  state: () => ({
6
- scrolled: import.meta.browser ? window.scrollY > 0 : false,
6
+ scrolled: typeof window !== "undefined" ? window.scrollY > 0 : false,
7
7
  loading: false,
8
8
  total: 0,
9
9
  skip: 0,
@@ -29,16 +29,18 @@ export const useRootStore = defineStore("rootStore", {
29
29
  setLoading(value, type = "") {
30
30
  const { $stores } = useNuxtApp();
31
31
  this.loading = value;
32
- if (type.length) $stores[type].loading = value;
32
+ if (type.length && $stores[type]) {
33
+ $stores[type].loading = value;
34
+ }
33
35
  },
34
36
  setScrolled() {
35
- if (import.meta.browser) {
37
+ if (typeof window !== "undefined") {
36
38
  this.scrolled = window.scrollY > 0;
37
39
  }
38
40
  },
39
41
  saveFiltersToLocalStorage(type) {
40
42
  const { $stores } = useNuxtApp();
41
- const filters = $stores[type].filters ?? {};
43
+ const filters = $stores[type]?.filters ?? {};
42
44
  const values = Object.fromEntries(
43
45
  Object.entries(filters).map(([key, filter]) => [key, filter.value])
44
46
  );
@@ -50,11 +52,14 @@ export const useRootStore = defineStore("rootStore", {
50
52
  const { $stores } = useNuxtApp();
51
53
  const { currentRoute } = useRouter();
52
54
  const query = currentRoute.value.query;
53
- const filters = $stores[type].filters;
55
+ const filters = $stores[type]?.filters ?? {};
54
56
  if (Object.keys(query)?.length) {
55
57
  Object.keys(query).forEach((filter) => {
56
58
  if (filter in filters) {
57
- filters[filter].value = filters[filter].multiple ? JSON.parse(query[filter]) : query[filter];
59
+ const queryValue = query[filter];
60
+ if (typeof queryValue === "string") {
61
+ filters[filter].value = filters[filter].multiple ? JSON.parse(queryValue) : queryValue;
62
+ }
58
63
  }
59
64
  });
60
65
  }
@@ -66,10 +71,10 @@ export const useRootStore = defineStore("rootStore", {
66
71
  const local = JSON.parse(localStorage.getItem("PARIS_IAS") || "{}");
67
72
  const saved = local[`${type}_filters`] ?? null;
68
73
  if (!saved) {
69
- console.log(`[${type}] Aucune donn\xE9e \xE0 restaurer.`);
74
+ console.log(`[${type}] No data to restore.`);
70
75
  return;
71
76
  }
72
- const filters = $stores[type].filters ?? {};
77
+ const filters = $stores[type]?.filters ?? {};
73
78
  for (const [key, value] of Object.entries(saved)) {
74
79
  if (filters[key]) {
75
80
  filters[key].value = value;
@@ -77,17 +82,19 @@ export const useRootStore = defineStore("rootStore", {
77
82
  }
78
83
  this.setFiltersCount(type);
79
84
  this.updateRouteQuery(type);
80
- console.log(`[${type}] Filtres restaur\xE9s depuis localStorage`, saved);
85
+ console.log(`[${type}] Filters restored from localStorage`, saved);
81
86
  },
82
87
  setFiltersCount(type) {
83
88
  const { $stores } = useNuxtApp();
84
- const filters = $stores[type].filters ?? {};
89
+ const filters = $stores[type]?.filters ?? {};
85
90
  const count = Object.values(filters).reduce((acc, filter) => {
86
91
  const value = filter?.value;
87
92
  const isEmpty = value === void 0 || value === null || Array.isArray(value) && value.length === 0 || typeof value === "string" && value.trim() === "";
88
93
  return isEmpty ? acc : acc + 1;
89
94
  }, 0);
90
- $stores[type].filtersCount = count;
95
+ if ($stores[type]) {
96
+ $stores[type].filtersCount = count;
97
+ }
91
98
  },
92
99
  updateRouteQuery(type) {
93
100
  const router = useRouter();
@@ -95,7 +102,7 @@ export const useRootStore = defineStore("rootStore", {
95
102
  const routeQuery = {
96
103
  ...this.search ? { search: this.search } : {},
97
104
  ...this.page > 1 ? { page: this.page.toString() } : {},
98
- ...Object.entries($stores[type].filters).reduce(
105
+ ...Object.entries($stores[type]?.filters ?? {}).reduce(
99
106
  (acc, [key, filter]) => {
100
107
  const value = filter?.value;
101
108
  console.log("valueStore", value);
@@ -103,7 +110,7 @@ export const useRootStore = defineStore("rootStore", {
103
110
  if (isEmpty) return acc;
104
111
  return {
105
112
  ...acc,
106
- [key]: Array.isArray(value) ? JSON.stringify(value) : value
113
+ [key]: Array.isArray(value) ? JSON.stringify(value) : String(value)
107
114
  };
108
115
  },
109
116
  {}
@@ -114,8 +121,9 @@ export const useRootStore = defineStore("rootStore", {
114
121
  resetState(type) {
115
122
  const { $stores, $models } = useNuxtApp();
116
123
  console.log("$models[type]: ", $models[type]);
117
- const store = $stores[type];
118
- $stores[type] = $models[type];
124
+ if ($models[type] && $stores[type]) {
125
+ $stores[type] = $models[type];
126
+ }
119
127
  console.log("resetState");
120
128
  this.search = "";
121
129
  this.page = 1;
@@ -127,32 +135,41 @@ export const useRootStore = defineStore("rootStore", {
127
135
  this.setFiltersCount(type);
128
136
  this.updateRouteQuery(type);
129
137
  },
130
- updateSort({ value, type }) {
138
+ updateSort({
139
+ value,
140
+ type
141
+ }) {
131
142
  const { $stores } = useNuxtApp();
132
- $stores[type].sortBy = [value[0]];
133
- $stores[type].sortDesc = [value[1]];
143
+ if ($stores[type]) {
144
+ $stores[type].sortBy = [String(value[0])];
145
+ $stores[type].sortDesc = [Number(value[1])];
146
+ }
134
147
  this.page = 1;
135
148
  this.updateLocalStorage(type + "_sort", value.join("_"));
136
149
  this.update(type);
137
150
  },
138
151
  updateView({ value, type }) {
139
152
  const { $stores } = useNuxtApp();
140
- $stores[type].view = {
141
- ...$stores[type].views[value],
142
- name: value
143
- };
153
+ if ($stores[type]?.views?.[value]) {
154
+ $stores[type].view = {
155
+ ...$stores[type].views[value],
156
+ name: value
157
+ };
158
+ }
144
159
  this.updateLocalStorage(type + "_view", value);
145
160
  this.update(type);
146
161
  },
147
162
  updateLocalStorage(key, value) {
148
- const local = JSON.parse(localStorage.getItem("PARIS_IAS")) || {};
163
+ const local = JSON.parse(localStorage.getItem("PARIS_IAS") || "{}");
149
164
  local[key] = value;
150
165
  localStorage.setItem("PARIS_IAS", JSON.stringify(local));
151
166
  },
152
167
  updateFilter(key, val, type) {
153
168
  const { $stores } = useNuxtApp();
154
169
  console.log("update filter: ", { key, val, type });
155
- $stores[type].filters[key].value = val;
170
+ if ($stores[type]?.filters?.[key]) {
171
+ $stores[type].filters[key].value = val;
172
+ }
156
173
  this.setFiltersCount(type);
157
174
  this.saveFiltersToLocalStorage(type);
158
175
  this.updateRouteQuery(type);
@@ -162,7 +179,9 @@ export const useRootStore = defineStore("rootStore", {
162
179
  updateItemsPerPage({ value, type }) {
163
180
  const { $stores } = useNuxtApp();
164
181
  this.page = 1;
165
- $stores[type].itemsPerPage = value;
182
+ if ($stores[type]) {
183
+ $stores[type].itemsPerPage = value;
184
+ }
166
185
  this.update(type);
167
186
  },
168
187
  updatePage({ page, type }) {
@@ -181,15 +200,16 @@ export const useRootStore = defineStore("rootStore", {
181
200
  async update(type, lang = "en") {
182
201
  const { $stores, $queries } = useNuxtApp();
183
202
  this.setLoading(true);
184
- if (type !== "all") {
203
+ if (type !== "all" && $stores[type]) {
185
204
  $stores[type].loading = true;
186
205
  }
187
- const itemsPerPage = type === "all" ? 3 : $stores[type]?.itemsPerPage;
206
+ const itemsPerPage = type === "all" ? 3 : $stores[type]?.itemsPerPage || 10;
188
207
  const filters = {};
189
208
  if (type !== "all") {
190
- for (const filter in $stores[type].filters) {
191
- const filterValue = $stores[type].filters[filter]?.value;
192
- if (typeof filterValue !== "undefined" && filterValue?.length) {
209
+ const storeFilters = $stores[type]?.filters ?? {};
210
+ for (const filter in storeFilters) {
211
+ const filterValue = storeFilters[filter]?.value;
212
+ if (typeof filterValue !== "undefined" && filterValue !== null && (Array.isArray(filterValue) ? filterValue.length > 0 : true)) {
193
213
  filters[filter] = filterValue;
194
214
  }
195
215
  }
@@ -202,8 +222,8 @@ export const useRootStore = defineStore("rootStore", {
202
222
  // limit
203
223
  limit: itemsPerPage,
204
224
  // sort, array of keys and array of directions - to have x tie breakers if necessary
205
- sortBy: type === "all" ? "searchScore" : $stores[type].sortBy,
206
- sortDesc: type === "all" ? -1 : $stores[type].sortDesc > 0 ? true : false,
225
+ sortBy: type === "all" ? "searchScore" : $stores[type]?.sortBy || ["created"],
226
+ sortDesc: type === "all" ? -1 : ($stores[type]?.sortDesc?.[0] || 0) > 0 ? true : false,
207
227
  // search (if set)
208
228
  ...this.search?.length && type !== "all" && { search: this.search },
209
229
  // add the store module filters
@@ -215,32 +235,33 @@ export const useRootStore = defineStore("rootStore", {
215
235
  })
216
236
  );
217
237
  args.options.filters = JSON.stringify(args.options.filters);
218
- let result = {};
219
238
  console.log("args: ", args);
220
239
  console.log(`Fetching ${type}`);
221
240
  const { data, error } = await useAsyncQuery(
222
- type === "all" ? SEARCH : $queries[type].list,
241
+ type === "all" ? SEARCH : $queries[type]?.list,
223
242
  args
224
243
  );
225
244
  console.log("data: ", data);
226
245
  if (error.value) console.log(error.value);
227
246
  const key = type === "all" ? "search" : "list" + type.charAt(0).toUpperCase() + type.slice(1);
228
247
  if (type === "all") {
229
- this.results = data?.value?.[key];
248
+ this.results = data?.value?.[key] || this.results;
230
249
  } else {
231
250
  const items = data?.value?.[key]?.items ?? [];
232
- $stores[type].total = data?.value?.[key]?.total;
233
- result = {
234
- ...data?.value?.[key],
235
- items: items.map(({ id, ...rest }) => ({
236
- ...rest,
237
- _path: `/${id}`
238
- }))
239
- };
240
- $stores[type].items = result["items"];
241
- const lastPage = Math.ceil(result.total / itemsPerPage);
242
- this.setFiltersCount(type);
243
- $stores[type].numberOfPages = lastPage;
251
+ if ($stores[type]) {
252
+ $stores[type].total = data?.value?.[key]?.total || 0;
253
+ const result = {
254
+ ...data?.value?.[key],
255
+ items: items.map(({ id, ...rest }) => ({
256
+ ...rest,
257
+ _path: `/${id}`
258
+ }))
259
+ };
260
+ $stores[type].items = result.items;
261
+ const lastPage = Math.ceil((result.total || 0) / itemsPerPage);
262
+ this.setFiltersCount(type);
263
+ $stores[type].numberOfPages = lastPage;
264
+ }
244
265
  }
245
266
  this.setLoading(false, type);
246
267
  return true;
@@ -338,5 +338,6 @@
338
338
  "visit-this-publications-website": "Visit this publication webpage",
339
339
  "close-the-filter-panel": "Close the filter panel",
340
340
  "list.by-vintage-from-recent-to-old": "By Year, from recent to old",
341
- "list.by-vintage-from-old-to-recent": "By Year, from old to recent"
341
+ "list.by-vintage-from-old-to-recent": "By Year, from old to recent",
342
+ "no-biography": "No biography available"
342
343
  }
@@ -336,5 +336,6 @@
336
336
  "groups": "Catégorie",
337
337
  "present": "aujourd'hui",
338
338
  "visit-this-project-website": "Visitez le site Web du projet",
339
- "visit-this-publications-website": "Visitez la page Web de cette publication"
339
+ "visit-this-publications-website": "Visitez la page Web de cette publication",
340
+ "no-biography": "Aucune biographie disponible"
340
341
  }
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.85",
4
+ "version": "1.0.87",
5
5
  "name": "@paris-ias/list",
6
6
  "repository": {
7
7
  "url": "git+https://github.com/IEA-Paris/list.git",
@@ -1,82 +0,0 @@
1
- <template>
2
- <v-card
3
- v-ripple
4
- class="event-sliding-item cursor-pointer"
5
- elevation="2"
6
- height="280"
7
- @click="$router.push(localePath('/activities/events/' + item.slug[locale]))"
8
- >
9
- <v-card-text class="pa-4 d-flex flex-column h-100">
10
- <!-- Date section -->
11
- <div class="text-overline font-weight-black mb-2 text-primary">
12
- {{
13
- new Date(item.start).toLocaleDateString(locale, {
14
- year: "numeric",
15
- month: "short",
16
- day: "numeric",
17
- })
18
- }}
19
- </div>
20
-
21
- <!-- Category badge -->
22
- <v-chip
23
- v-if="item.category"
24
- size="small"
25
- variant="outlined"
26
- color="primary"
27
- class="mb-3 align-self-start"
28
- >
29
- {{ $t("list.filters.events.category." + item.category) }}
30
- </v-chip>
31
-
32
- <!-- Event title -->
33
- <h3 class="text-h6 font-weight-bold mb-3 line-clamp-3">
34
- {{ item.name }}
35
- </h3>
36
-
37
- <!-- Event description if available -->
38
- <p v-if="item.description" class="text-body-2 text-grey-darken-2 line-clamp-4 flex-grow-1">
39
- {{ item.description }}
40
- </p>
41
-
42
- <!-- Location if available -->
43
- <div v-if="item.location" class="mt-auto pt-2">
44
- <v-icon size="small" class="mr-1">mdi-map-marker</v-icon>
45
- <span class="text-caption text-grey-darken-1">{{ item.location }}</span>
46
- </div>
47
- </v-card-text>
48
-
49
- <!-- Hover overlay -->
50
- <v-overlay
51
- v-model="isHovered"
52
- contained
53
- opacity="0.1"
54
- class="d-flex align-center justify-center"
55
- >
56
- <v-icon size="large" color="primary">mdi-eye</v-icon>
57
- </v-overlay>
58
- </v-card>
59
- </template>
60
-
61
- <script setup>
62
- import { ref } from "vue";
63
- import { useLocalePath, useI18n } from "#imports";
64
- const { locale } = useI18n();
65
- const localePath = useLocalePath();
66
- const props = defineProps({
67
- item: {
68
- type: Object,
69
- required: true
70
- },
71
- index: {
72
- type: Number,
73
- required: true
74
- }
75
- });
76
- const { item, index } = props;
77
- const isHovered = ref(false);
78
- </script>
79
-
80
- <style scoped>
81
- .event-sliding-item{border-radius:12px;overflow:hidden;transition:all .3s cubic-bezier(.25,.8,.25,1)}.event-sliding-item:hover{box-shadow:0 8px 25px rgba(0,0,0,.15)!important;transform:translateY(-4px)}.line-clamp-3{-webkit-line-clamp:3;line-clamp:3}.line-clamp-3,.line-clamp-4{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.line-clamp-4{-webkit-line-clamp:4;line-clamp:4}
82
- </style>