@paris-ias/list 1.0.105 → 1.0.107

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.105",
4
+ "version": "1.0.107",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.0",
7
7
  "unbuild": "3.5.0"
@@ -1,32 +1,50 @@
1
1
  <template>
2
2
  <v-row
3
3
  v-ripple
4
+ no-gutters
4
5
  class="cursor-pointer highlight-on-hover"
5
6
  @click="$router.push(localePath('/activities/events/' + item.slug[locale]))"
6
7
  >
7
- <v-col align-self="center" cols="2">
8
- {{
9
- new Date(item.start).toLocaleDateString(locale, {
10
- year: "numeric",
11
- month: "numeric",
12
- day: "numeric",
13
- })
14
- }}
8
+ <v-col v-if="mdAndUp" align-self="center" cols="1">
9
+ <MiscAtomsImageContainer
10
+ cover
11
+ :loading="$stores.events.loading"
12
+ :src="item.image.url ? item.image : '/default.png'"
13
+ :ratio="1 / 1"
14
+ :name="item.name"
15
+ :slug="item.slug"
16
+ link="events-slug"
17
+ width="80px"
18
+ />
15
19
  </v-col>
16
- <v-col align-self="center" class="text-h6 dense">
17
- <div class="mt-2 text-h6 text-overline font-weight-black">
18
- {{ $t("list.filters.events.category." + item.category) }}
20
+
21
+ <v-col align-self="center" class="pl-2">
22
+ <div class="text-h5 dense text-overline font-weight-black">
23
+ {{
24
+ $t("list.filters.events.category." + item.category) +
25
+ " / " +
26
+ new Date(item.start).toLocaleDateString(locale, {
27
+ year: "numeric",
28
+ month: "numeric",
29
+ day: "numeric",
30
+ })
31
+ }}
32
+ </div>
33
+ <div class="text-h5 dense">
34
+ {{ item.name }}
19
35
  </div>
20
- {{ item.name }}
21
36
  </v-col>
22
- <v-col align-self="center">
23
- <!-- <EventsBadges :item /> -->
37
+
38
+ <v-col align-self="center" cols="auto">
39
+ <EventsBadges :item />
24
40
  </v-col>
25
41
  </v-row>
26
42
  </template>
27
43
 
28
44
  <script setup>
29
45
  import { useLocalePath, useI18n } from "#imports";
46
+ import { useDisplay } from "vuetify";
47
+ const { mdAndUp } = useDisplay();
30
48
  const { locale } = useI18n();
31
49
  const localePath = useLocalePath();
32
50
  const props = defineProps({
@@ -1,12 +1,13 @@
1
1
  <template>
2
2
  <v-row
3
3
  v-ripple
4
+ no-gutters
4
5
  class="cursor-pointer highlight-on-hover"
5
6
  @click="
6
7
  $router.push(localePath('/activities/fellowships' + item.slug[locale]))
7
8
  "
8
9
  >
9
- <v-col align-self="center" cols="8" class="text-h6">
10
+ <v-col align-self="center" cols="8" class="text-h5 dense">
10
11
  {{ item.name }}
11
12
  <FellowshipsBadges :item="item" />
12
13
  </v-col>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <component
3
+ :is="itemTemplate"
4
+ v-for="(item, index) in $rootStore.results[type].items"
5
+ :key="index"
6
+ :item="item"
7
+ :index="index"
8
+ />
9
+ </template>
10
+
11
+ <script setup>
12
+ import { capitalize } from "../../../composables/useUtils";
13
+ import { useNuxtApp, resolveComponent, computed } from "#imports";
14
+ const { $stores, $rootStore } = useNuxtApp();
15
+ console.log("rootStore: ", $rootStore);
16
+ const props = defineProps({
17
+ type: {
18
+ type: String,
19
+ default: "people"
20
+ }
21
+ });
22
+ const itemTemplate = computed(
23
+ () => resolveComponent(
24
+ (capitalize(props.type) + capitalize($stores[props.type].view.name) + "Item").toString()
25
+ )
26
+ );
27
+ </script>
@@ -1,80 +1,83 @@
1
1
  <template>
2
2
  <div class="d-flex flex-grow-1 flex-column">
3
- <v-text-field
4
- v-model.trim="search"
5
- :placeholder="$t('list.search-type', [$t('items.' + type, 2)])"
6
- prepend-inner-icon="mdi-magnify"
7
- single-line
8
- class="transition-swing"
9
- variant="outlined"
10
- hide-details
11
- clearable
12
- tile
13
- type="search"
14
- :loading="rootStore.loading"
15
- >
16
- <!-- :loading="$nuxt.loading || $store.state.loading" :class="{ 'mt-3':
17
- $store.state.scrolled }" -->
18
- <template v-if="!search" #label>
19
- <div class="searchLabel">
20
- {{
21
- type === "all"
22
- ? $t("search")
23
- : $t("list.search-type", [$t("items." + type, 2)])
24
- }}
25
- </div>
26
- </template>
27
- </v-text-field>
28
- <v-expand-transition v-if="type === 'all'">
29
- <v-list
30
- v-show="search.length"
31
- lines="three"
32
- item-props
33
- style="max-height: 300px"
34
- class="overflow-y-auto"
3
+ <div class="d-flex align-center">
4
+ <v-text-field
5
+ v-model.trim="search"
6
+ :placeholder="$t('list.search-type', [$t('items.' + type, 2)])"
7
+ prepend-inner-icon="mdi-magnify"
8
+ single-line
9
+ class="transition-swing flex-grow-1"
10
+ variant="outlined"
11
+ hide-details
12
+ clearable
13
+ tile
14
+ type="search"
15
+ :loading="rootStore.loading"
35
16
  >
36
- <div v-if="rootStore.loading" class="d-flex justify-center py-6">
37
- <v-progress-circular color="black" size="64" indeterminate />
38
- </div>
39
- <template v-for="(item, index) in results">
40
- <v-list-subheader
41
- v-if="item.type && item.type === 'subheader'"
42
- :key="'subheader-' + index"
43
- >
44
- {{ $t(item.name) }}
45
- </v-list-subheader>
46
- <div
47
- v-else-if="item.type && item.type === 'no-result'"
48
- :key="'no-result-' + index"
49
- class="mx-6"
50
- >
51
- {{ $t("no-result") }}
17
+ <!-- :loading="$nuxt.loading || $store.state.loading" :class="{ 'mt-3':
18
+ $store.state.scrolled }" -->
19
+ <template v-if="!search" #label>
20
+ <div class="searchLabel">
21
+ {{
22
+ type === "all"
23
+ ? $t("search")
24
+ : $t("list.search-type", [$t("items." + type, 2)])
25
+ }}
52
26
  </div>
53
- <v-divider
54
- v-else-if="item.type && item.type === 'divider'"
55
- :key="'divider-' + index"
56
- inset
57
- />
58
- <ListAtomsSearchItem
59
- v-else
60
- :key="'item- ' + index"
61
- :index
62
- :item
63
- :type="item.type"
64
- />
65
27
  </template>
66
- </v-list>
67
- </v-expand-transition>
28
+ </v-text-field>
29
+
30
+ <v-menu
31
+ v-model="filterMenuOpen"
32
+ :close-on-content-click="false"
33
+ location="bottom end"
34
+ offset="4"
35
+ >
36
+ <template #activator="{ props: menuProps }">
37
+ <v-btn
38
+ v-bind="menuProps"
39
+ :rounded="0"
40
+ variant="outlined"
41
+ size="large"
42
+ height="56"
43
+ >
44
+ <v-icon>mdi-filter</v-icon>
45
+ <v-icon class="ml-1" size="small">
46
+ {{ filterMenuOpen ? "mdi-chevron-up" : "mdi-chevron-down" }}
47
+ </v-icon>
48
+ </v-btn>
49
+ </template>
50
+
51
+ <v-card min-width="200">
52
+ <v-list>
53
+ <v-list-item
54
+ v-for="option in filterOptions"
55
+ :key="option.value"
56
+ @click="toggleFilter(option)"
57
+ >
58
+ <template #prepend>
59
+ <v-checkbox
60
+ hide-details
61
+ :model-value="selectedFilters.includes(option.value)"
62
+ @update:model-value="toggleFilter(option)"
63
+ />
64
+ </template>
65
+ <v-list-item-title>{{ option.label }}</v-list-item-title>
66
+ </v-list-item>
67
+ </v-list>
68
+ </v-card>
69
+ </v-menu>
70
+ </div>
68
71
  </div>
69
72
  </template>
70
73
 
71
74
  <script setup>
72
75
  import { useDebounceFn } from "@vueuse/core";
73
76
  import { useRootStore } from "../../../stores/root";
74
- import { useNuxtApp, computed, useI18n } from "#imports";
77
+ import { computed, useI18n, ref } from "#imports";
75
78
  const { locale, t } = useI18n();
76
79
  const rootStore = useRootStore();
77
- const { $stores } = useNuxtApp();
80
+ const emit = defineEmits(["filter-change"]);
78
81
  const props = defineProps({
79
82
  type: {
80
83
  type: String,
@@ -85,34 +88,29 @@ const props = defineProps({
85
88
  default: false
86
89
  }
87
90
  });
88
- const results = computed(() => {
89
- const storeRst = rootStore.results;
90
- const rst = Object.keys(storeRst).length && Object.keys(storeRst).sort((a, b) => {
91
- return storeRst[b]?.items?.length - storeRst[a]?.items?.length;
92
- }).reduce((acc, key, index) => {
93
- const items = storeRst[key]?.items;
94
- const total = storeRst[key]?.total;
95
- if (total === 0 && index === 0) {
96
- acc.push({ type: "no-result" });
97
- return acc;
98
- }
99
- if (items?.length) {
100
- acc.push({ type: "subheader", name: t("items." + key, 2) });
101
- acc.push(
102
- ...items.map((item) => ({
103
- prependAvatar: item?.image?.url || "mdi-square",
104
- title: item.name || item.firstname + " " + item.lastname,
105
- subtitle: item.summary || item.biography,
106
- id: item.id,
107
- type: key
108
- }))
109
- );
110
- }
111
- acc.push({ type: "divider" });
112
- return acc;
113
- }, []) || {};
114
- return rst;
115
- });
91
+ const filterMenuOpen = ref(false);
92
+ const selectedFilters = ref([]);
93
+ const filterOptions = [
94
+ { value: "people", label: capitalize(t("items.people", 2)) },
95
+ { value: "events", label: capitalize(t("items.events", 2)) },
96
+ { value: "news", label: capitalize(t("items.news", 2)) },
97
+ { value: "publications", label: capitalize(t("items.publications", 2)) },
98
+ { value: "fellowships", label: capitalize(t("items.fellowships", 2)) },
99
+ { value: "projects", label: capitalize(t("items.projects", 2)) }
100
+ ];
101
+ const toggleFilter = (option) => {
102
+ const index = selectedFilters.value.indexOf(option.value);
103
+ if (index > -1) {
104
+ selectedFilters.value.splice(index, 1);
105
+ } else {
106
+ selectedFilters.value.push(option.value);
107
+ }
108
+ emit("filter-change", {
109
+ name: option.value,
110
+ value: selectedFilters.value.includes(option.value),
111
+ allSelected: selectedFilters.value
112
+ });
113
+ };
116
114
  const search = computed({
117
115
  get() {
118
116
  return rootStore.search;
@@ -14,7 +14,7 @@
14
14
  $stores[type].total,
15
15
  $t("items." + props.type, $stores[type].total),
16
16
  ],
17
- $stores[type].total
17
+ $stores[type].total,
18
18
  )
19
19
  : $t(
20
20
  "list.0-items-found",
@@ -22,7 +22,7 @@
22
22
  $stores[type].total,
23
23
  $t("items." + props.type, $stores[type].total),
24
24
  ],
25
- $stores[type].total
25
+ $stores[type].total,
26
26
  )
27
27
  }}
28
28
  </template>
@@ -42,11 +42,11 @@
42
42
  $t(
43
43
  "items." + props.type,
44
44
  $stores[type].total,
45
- $stores[type].total
45
+ $stores[type].total,
46
46
  ),
47
47
  $stores[type].search,
48
48
  ],
49
- $stores[type].total
49
+ $stores[type].total,
50
50
  )
51
51
  : $t(
52
52
  "list.0-items-found-searching-for",
@@ -55,11 +55,11 @@
55
55
  $t(
56
56
  "items." + props.type,
57
57
  $stores[type].total,
58
- $stores[type].total
58
+ $stores[type].total,
59
59
  ),
60
60
  $stores[type].search,
61
61
  ],
62
- $stores[type].total
62
+ $stores[type].total,
63
63
  )
64
64
  }}
65
65
  </template>
@@ -79,12 +79,12 @@
79
79
  $t(
80
80
  "items." + props.type,
81
81
  $stores[type].total,
82
- $stores[type].total
82
+ $stores[type].total,
83
83
  ),
84
84
  $stores[type].filtersCount,
85
85
  $t("filters", $stores[type].filtersCount),
86
86
  ],
87
- $stores[type].total
87
+ $stores[type].total,
88
88
  )
89
89
  : $t(
90
90
  "list.0-items-found-with-1-filter",
@@ -94,7 +94,7 @@
94
94
  $stores[type].filtersCount,
95
95
  $t("filters", $stores[type].filtersCount),
96
96
  ],
97
- $stores[type].total
97
+ $stores[type].total,
98
98
  )
99
99
  }}
100
100
  </template>
@@ -117,7 +117,7 @@
117
117
  $stores[type].filtersCount,
118
118
  $t("filters", $stores[type].filtersCount),
119
119
  ],
120
- $stores[type].total
120
+ $stores[type].total,
121
121
  )
122
122
  : $t(
123
123
  "list.0-items-found-searching-for-with-1-filter",
@@ -128,7 +128,7 @@
128
128
  $stores[type].filtersCount,
129
129
  $t("filters", $stores[type].filtersCount),
130
130
  ],
131
- $stores[type].total
131
+ $stores[type].total,
132
132
  )
133
133
  }}
134
134
  </template>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div class="d-flex flex-grow-1 flex-column">
3
+ <div class="d-flex align-center">
4
+ <v-text-field
5
+ v-model.trim="search"
6
+ :placeholder="$t('list.search-type', [$t('items.' + type, 2)])"
7
+ prepend-inner-icon="mdi-magnify"
8
+ single-line
9
+ class="transition-swing flex-grow-1"
10
+ variant="outlined"
11
+ hide-details
12
+ clearable
13
+ tile
14
+ type="search"
15
+ :loading="rootStore.loading"
16
+ >
17
+ <!-- :loading="$nuxt.loading || $store.state.loading" :class="{ 'mt-3':
18
+ $store.state.scrolled }" -->
19
+ <template v-if="!search" #label>
20
+ <div class="searchLabel">
21
+ {{
22
+ type === "all"
23
+ ? $t("search")
24
+ : $t("list.search-type", [$t("items." + type, 2)])
25
+ }}
26
+ </div>
27
+ </template>
28
+ </v-text-field>
29
+
30
+ <v-menu
31
+ v-model="filterMenuOpen"
32
+ :close-on-content-click="false"
33
+ location="bottom end"
34
+ offset="4"
35
+ >
36
+ <template #activator="{ props: menuProps }">
37
+ <v-btn
38
+ v-bind="menuProps"
39
+ :rounded="0"
40
+ variant="outlined"
41
+ size="large"
42
+ height="56"
43
+ >
44
+ <v-icon>mdi-filter</v-icon>
45
+ <v-icon class="ml-1" size="small">
46
+ {{ filterMenuOpen ? "mdi-chevron-up" : "mdi-chevron-down" }}
47
+ </v-icon>
48
+ </v-btn>
49
+ </template>
50
+
51
+ <v-card min-width="200">
52
+ <v-list density="compact">
53
+ <v-list-item
54
+ v-for="(option, index) in filterOptions"
55
+ :key="option.value"
56
+ @click="toggleFilter(option)"
57
+ >
58
+ <template #prepend>
59
+ <v-checkbox
60
+ hide-details
61
+ :model-value="categories.includes(index)"
62
+ @update:model-value="toggleFilter(option)"
63
+ />
64
+ </template>
65
+ <v-list-item-title>{{ option.label }}</v-list-item-title>
66
+ </v-list-item>
67
+ </v-list>
68
+ </v-card>
69
+ </v-menu>
70
+ </div>
71
+ </div>
72
+ </template>
73
+
74
+ <script setup>
75
+ import { useDebounceFn } from "@vueuse/core";
76
+ import { useRootStore } from "../../../stores/root";
77
+ import { computed, useI18n, ref } from "#imports";
78
+ const { locale, t } = useI18n();
79
+ const rootStore = useRootStore();
80
+ const emit = defineEmits(["filter-change"]);
81
+ const props = defineProps({
82
+ type: {
83
+ type: String,
84
+ required: true
85
+ },
86
+ loading: {
87
+ type: Boolean,
88
+ default: false
89
+ },
90
+ categories: {
91
+ type: Array,
92
+ default: () => []
93
+ }
94
+ });
95
+ const filterMenuOpen = ref(false);
96
+ const filterOptions = [
97
+ { value: "people", label: capitalize(t("items.people", 2)) },
98
+ { value: "events", label: capitalize(t("items.events", 2)) },
99
+ { value: "news", label: capitalize(t("items.news", 2)) },
100
+ { value: "publications", label: capitalize(t("items.publications", 2)) },
101
+ { value: "fellowships", label: capitalize(t("items.fellowships", 2)) },
102
+ { value: "projects", label: capitalize(t("items.projects", 2)) }
103
+ ];
104
+ const toggleFilter = (option) => {
105
+ const index = props.categories.indexOf(option.value);
106
+ if (index > -1) {
107
+ props.categories.splice(index, 1);
108
+ } else {
109
+ props.categories.push(option.value);
110
+ }
111
+ emit("filter-change", {
112
+ name: option.value,
113
+ value: props.categories.includes(option.value)
114
+ });
115
+ };
116
+ const search = computed({
117
+ get() {
118
+ return rootStore.search;
119
+ },
120
+ set: await useDebounceFn(async function(v) {
121
+ await rootStore.updateSearch({
122
+ type: props.type,
123
+ search: v || "",
124
+ lang: locale.value
125
+ });
126
+ }, 300)
127
+ });
128
+ </script>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <div>
3
+ <v-divider />
4
+ <div class="d-flex align-center justify-space-between my-6">
5
+ <v-btn
6
+ variant="text"
7
+ size="large"
8
+ class=""
9
+ @click="$emit('toggle', type)"
10
+ >
11
+ <v-icon size="large">{{
12
+ open ? "mdi-chevron-down" : "mdi-chevron-right"
13
+ }}</v-icon>
14
+ </v-btn>
15
+ <div
16
+ class="d-flex flex-column cursor-pointer"
17
+ @click="$emit('toggle', type)"
18
+ >
19
+ <div class="text-h4">
20
+ {{ capitalize($t("items." + props.type, 2)) }}
21
+ </div>
22
+ <div class="text-overline">
23
+ {{
24
+ feminine
25
+ ? $t(
26
+ "list.0-items-found-f",
27
+ [
28
+ $rootStore.results[type].total,
29
+ $t("items." + props.type, $rootStore.results[type].total),
30
+ ],
31
+ $rootStore.results[type].total,
32
+ )
33
+ : $t(
34
+ "list.0-items-found",
35
+ [
36
+ $rootStore.results[type].total,
37
+ $t("items." + props.type, $rootStore.results[type].total),
38
+ ],
39
+ $rootStore.results[type].total,
40
+ )
41
+ }}
42
+ </div>
43
+ </div>
44
+ <v-spacer />
45
+ <v-btn
46
+ class="ma-2"
47
+ color="default"
48
+ variant="outlined"
49
+ rounded="0"
50
+ :to="localePath(type === 'people' ? '/people' : '/activities/' + type)"
51
+ >
52
+ {{ $t("list.pls-x-more", [$rootStore.results[type].total]) }}
53
+ </v-btn>
54
+ </div>
55
+ <slot />
56
+ </div>
57
+ </template>
58
+
59
+ <script setup>
60
+ import { useNuxtApp, useLocalePath } from "#imports";
61
+ const localePath = useLocalePath();
62
+ const { $rootStore } = useNuxtApp();
63
+ const props = defineProps({
64
+ type: {
65
+ type: String,
66
+ required: true
67
+ },
68
+ feminine: {
69
+ type: Boolean,
70
+ required: false,
71
+ default: false
72
+ },
73
+ open: {
74
+ type: Boolean,
75
+ required: false,
76
+ default: true
77
+ }
78
+ });
79
+ </script>
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <ListMoleculesGlobalSearchInput
3
+ type="all"
4
+ :placeholder="$t('search')"
5
+ variant="outlined"
6
+ />
7
+ <ListMoleculesResultsContainer
8
+ v-for="(type, index) in appConfig.list.modules"
9
+ :key="index"
10
+ :feminine="type === 'people'"
11
+ :type
12
+ :open="$rootStore.results[type].total > 0"
13
+ @toggle="open[$event] = !open[$event]"
14
+ >
15
+ <v-expand-transition class="results-container">
16
+ <div v-show="open[type]">
17
+ <ListAtomsResultsList :type />
18
+ </div> </v-expand-transition
19
+ ></ListMoleculesResultsContainer>
20
+ </template>
21
+
22
+ <script setup>
23
+ import {
24
+ onBeforeUnmount,
25
+ onMounted,
26
+ useI18n,
27
+ useAppConfig,
28
+ useNuxtApp
29
+ } from "#imports";
30
+ const { $rootStore } = useNuxtApp();
31
+ const appConfig = useAppConfig();
32
+ const { locale } = useI18n();
33
+ const open = ref({});
34
+ onMounted(() => {
35
+ console.log("mounted list");
36
+ });
37
+ try {
38
+ await $rootStore.update("all", locale.value);
39
+ } catch (error) {
40
+ console.log("error fetching update list: ", error);
41
+ }
42
+ onBeforeUnmount(() => {
43
+ });
44
+ </script>
45
+
46
+ <style scoped>
47
+ .results-container{display:flex;flex-direction:column;gap:8px;margin-left:8px}
48
+ </style>
@@ -1,22 +1,32 @@
1
1
  <template>
2
2
  <v-row
3
3
  v-ripple
4
+ no-gutters
4
5
  class="cursor-pointer highlight-on-hover"
5
- @click="$router.push(localePath('/news/' + item.slug[locale]))"
6
+ @click="$router.push(localePath('/activities/news/' + item.slug[locale]))"
6
7
  >
7
- <v-col align-self="center" cols="7" class="text-h6 dense">
8
- <v-skeleton-loader
9
- v-if="rootStore.loading || $stores[type].loading"
10
- type="heading"
8
+ <v-col v-if="mdAndUp" align-self="center" cols="1">
9
+ <MiscAtomsImageContainer
10
+ cover
11
+ :loading="$stores.people.loading"
12
+ :src="item.image.url ? item.image : '/default.png'"
13
+ :ratio="1 / 1"
14
+ :name="item.lastname + ' ' + item.firstname"
15
+ :slug="item.slug"
16
+ link="people-slug"
17
+ width="80px"
11
18
  />
19
+ </v-col>
20
+ <v-col align-self="center" class="text-h5 dense pl-2">
21
+ <v-skeleton-loader v-if="rootStore.loading" type="heading" />
12
22
  <template v-else>
13
23
  {{ item.name }}
14
24
  </template>
15
25
  </v-col>
16
26
 
17
- <v-col align-self="center" cols="5" class="dense">
27
+ <v-col align-self="center">
18
28
  <v-skeleton-loader
19
- v-if="rootStore.loading || $stores[type].loading"
29
+ v-if="rootStore.loading"
20
30
  :type="
21
31
  ['chip', 'chip@2', 'chip@3', 'chip@4', 'chip@4', 'chip@4'][
22
32
  ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].indexOf(name || 'md')
@@ -39,7 +49,7 @@ import { useDisplay } from "vuetify";
39
49
  import { useRootStore } from "../../stores/root";
40
50
  import { computed, useNuxtApp, useI18n, useLocalePath } from "#imports";
41
51
  const { $stores } = useNuxtApp();
42
- const { name } = useDisplay();
52
+ const { name, mdAndUp } = useDisplay();
43
53
  const localePath = useLocalePath();
44
54
  const { locale } = useI18n();
45
55
  const rootStore = useRootStore();
@@ -77,7 +77,7 @@
77
77
  size="small"
78
78
  :to="
79
79
  localePath({
80
- name: 'news-slug',
80
+ name: 'activities-news-slug',
81
81
  params: { slug: item.slug[locale] },
82
82
  })
83
83
  "
@@ -114,7 +114,7 @@
114
114
  tile
115
115
  :to="
116
116
  localePath({
117
- name: 'news-slug',
117
+ name: 'activities-news-slug',
118
118
  params: { slug: item.slug[locale] },
119
119
  })
120
120
  "
@@ -3,18 +3,37 @@
3
3
  v-ripple
4
4
  no-gutters
5
5
  class="cursor-pointer highlight-on-hover"
6
- @click="$router.push(localePath('/people/' + item.slug))"
6
+ @click="
7
+ $router.push(
8
+ localePath({
9
+ name: 'people-slug',
10
+ params: { slug: item.slug },
11
+ }),
12
+ )
13
+ "
7
14
  >
8
- <v-col align-self="center" class="text-h6 pl-2">
9
- <v-skeleton-loader
10
- v-if="rootStore.loading || $stores[type].loading"
11
- type="heading"
15
+ <v-col v-if="mdAndUp" align-self="center" cols="1">
16
+ <MiscAtomsImageContainer
17
+ cover
18
+ :loading="$stores.people.loading"
19
+ :src="item.image.url ? item.image : '/default.png'"
20
+ :ratio="1 / 1"
21
+ :name="item.lastname + ' ' + item.firstname"
22
+ :slug="item.slug"
23
+ link="people-slug"
24
+ width="80px"
12
25
  />
13
- <template v-else>
26
+ </v-col>
27
+ <v-col align-self="center" class="text-h6 dense pl-2">
28
+ <v-skeleton-loader v-if="rootStore.loading" type="heading" />
29
+ <div v-else class="text-h5">
14
30
  {{ item.firstname + " " + item.lastname }}
15
- </template>
31
+ </div>
32
+ <div class="mt-2 text-body-2 font-weight-light">
33
+ {{ item.groups.vintage ? item.groups.vintage[0].theme : "" }}
34
+ </div>
16
35
  </v-col>
17
- <v-col align-self="center">
36
+ <v-col align-self="center" cols="auto">
18
37
  <PeopleGroupBadges :item="item" />
19
38
  </v-col>
20
39
  </v-row>
@@ -23,6 +42,8 @@
23
42
  <script setup>
24
43
  import { useRootStore } from "../../stores/root";
25
44
  import { useNuxtApp, useLocalePath } from "#imports";
45
+ import { useDisplay } from "vuetify";
46
+ const { mdAndUp } = useDisplay();
26
47
  const { $stores } = useNuxtApp();
27
48
  const localePath = useLocalePath();
28
49
  const rootStore = useRootStore();
@@ -4,39 +4,37 @@
4
4
  v-if="rootStore.loading || $stores.people.loading"
5
5
  type="chip"
6
6
  />
7
+ <template v-else-if="item.groups">
8
+ <template v-for="(value, key, index) in item.groups" :key="key + index">
9
+ <template v-if="value && key === 'vintage'">
10
+ <v-chip
11
+ v-for="(vintage, index2) in item.groups.vintage"
12
+ :key="index2"
13
+ class="mt-3 mr-3"
14
+ variant="outlined"
15
+ tile
16
+ style="background-color: white; color: black"
17
+ >
18
+ {{ $t("vintage", [vintage.year]) }}
19
+ </v-chip>
20
+ </template>
7
21
 
8
- <template
9
- v-for="(value, key, index) in item.groups"
10
- v-else
11
- :key="key + index"
12
- >
13
- <template v-if="value && key === 'vintage'">
14
22
  <v-chip
15
- v-for="(vintage, index2) in item.groups.vintage"
16
- :key="index2"
23
+ v-if="
24
+ value &&
25
+ key !== 'fellows' &&
26
+ ((!item.groups.vintage && key === 'vintage') ||
27
+ !['vintage', '__typename'].includes(key))
28
+ "
17
29
  class="mt-3 mr-3"
18
- variant="outlined"
19
- tile
30
+ color="black"
20
31
  style="background-color: white; color: black"
32
+ tile
33
+ variant="outlined"
21
34
  >
22
- {{ $t("vintage", [vintage.year]) }}
35
+ {{ $t("list.filters.people.groups." + key) }}
23
36
  </v-chip>
24
37
  </template>
25
-
26
- <v-chip
27
- v-if="
28
- value &&
29
- ((!item.groups.vintage && key === 'vintage') ||
30
- !['vintage', '__typename'].includes(key))
31
- "
32
- class="mt-3 mr-3"
33
- color="black"
34
- style="background-color: white; color: black"
35
- tile
36
- variant="outlined"
37
- >
38
- {{ $t("list.filters.people.groups." + key) }}
39
- </v-chip>
40
38
  </template>
41
39
  </div>
42
40
  </template>
@@ -49,7 +47,8 @@ const { $stores } = useNuxtApp();
49
47
  const props = defineProps({
50
48
  item: {
51
49
  type: Object,
52
- required: true
50
+ required: true,
51
+ default: () => ({})
53
52
  }
54
53
  });
55
54
  </script>
@@ -0,0 +1,77 @@
1
+ <template>
2
+ <v-row
3
+ v-ripple
4
+ no-gutters
5
+ class="cursor-pointer highlight-on-hover"
6
+ @click="
7
+ $router.push(
8
+ localePath({
9
+ name: 'activities-projects-slug',
10
+ params: { slug: item.slug[locale] },
11
+ }),
12
+ )
13
+ "
14
+ >
15
+ <v-col v-if="mdAndUp" align-self="center" cols="1">
16
+ <MiscAtomsImageContainer
17
+ cover
18
+ :loading="$stores.projects.loading"
19
+ :src="item.image.url ? item.image : '/default.png'"
20
+ :ratio="1 / 1"
21
+ :name="item.name"
22
+ :slug="item.slug[locale]"
23
+ link="activities-projects-slug"
24
+ width="50"
25
+ />
26
+ </v-col>
27
+ <v-col align-self="center" class="text-h5 dense pl-2">
28
+ <v-skeleton-loader v-if="rootStore.loading" type="heading" />
29
+ <template v-else>
30
+ {{ item.name }}
31
+ </template>
32
+ </v-col>
33
+
34
+ <v-col align-self="center" cols="5" class="dense">
35
+ <v-skeleton-loader
36
+ v-if="rootStore.loading"
37
+ :type="
38
+ ['chip', 'chip@2', 'chip@3', 'chip@4', 'chip@4', 'chip@4'][
39
+ ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].indexOf(name || 'md')
40
+ ]
41
+ "
42
+ />
43
+
44
+ <template v-else>
45
+ <MiscMoleculesChipContainer :items="item.tags" size="small" />
46
+ </template>
47
+ </v-col>
48
+ </v-row>
49
+ </template>
50
+
51
+ <script setup>
52
+ import { useDisplay } from "vuetify";
53
+ import { useRootStore } from "../../stores/root";
54
+ import { computed, useNuxtApp, useI18n, useLocalePath } from "#imports";
55
+ const { $stores } = useNuxtApp();
56
+ const { name, mdAndUp } = useDisplay();
57
+ const localePath = useLocalePath();
58
+ const { locale } = useI18n();
59
+ const rootStore = useRootStore();
60
+ const props = defineProps({
61
+ item: {
62
+ type: Object,
63
+ required: true
64
+ },
65
+ index: {
66
+ type: Number,
67
+ required: true
68
+ }
69
+ });
70
+ const eventCategory = computed(() => {
71
+ if (props.item.category) {
72
+ return "list.filters.news.category." + props.item.category;
73
+ } else {
74
+ return "list.filters.news.category.others";
75
+ }
76
+ });
77
+ </script>
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <v-row
3
+ v-ripple
4
+ no-gutters
5
+ class="cursor-pointer highlight-on-hover"
6
+ @click="
7
+ $router.push(localePath('/activities/publications/' + item.slug[locale]))
8
+ "
9
+ >
10
+ <v-col v-if="mdAndUp" align-self="center" cols="1">
11
+ <MiscAtomsImageContainer
12
+ cover
13
+ :loading="$stores.people.loading"
14
+ :src="item.image.url ? item.image : '/default.png'"
15
+ :ratio="1 / 1"
16
+ :name="item.lastname + ' ' + item.firstname"
17
+ :slug="item.slug[locale]"
18
+ link="activities-publications-slug"
19
+ width="80px"
20
+ />
21
+ </v-col>
22
+ <v-col align-self="center" class="text-h5 dense pl-2">
23
+ <v-skeleton-loader v-if="rootStore.loading" type="heading" />
24
+ <template v-else>
25
+ {{ item.name }}
26
+ </template>
27
+ </v-col>
28
+
29
+ <v-col align-self="center">
30
+ <v-skeleton-loader
31
+ v-if="rootStore.loading"
32
+ :type="
33
+ ['chip', 'chip@2', 'chip@3', 'chip@4', 'chip@4', 'chip@4'][
34
+ ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].indexOf(name || 'md')
35
+ ]
36
+ "
37
+ />
38
+
39
+ <template v-else>
40
+ <v-chip class="ma-2" style="background-color: white; color: black">
41
+ {{ $t(eventCategory) }}
42
+ </v-chip>
43
+ <MiscMoleculesChipContainer :items="item.tags" size="small" />
44
+ </template>
45
+ </v-col>
46
+ </v-row>
47
+ </template>
48
+
49
+ <script setup>
50
+ import { useDisplay } from "vuetify";
51
+ import { useRootStore } from "../../stores/root";
52
+ import { computed, useNuxtApp, useI18n, useLocalePath } from "#imports";
53
+ const { $stores } = useNuxtApp();
54
+ const { name, mdAndUp } = useDisplay();
55
+ const localePath = useLocalePath();
56
+ const { locale } = useI18n();
57
+ const rootStore = useRootStore();
58
+ const props = defineProps({
59
+ item: {
60
+ type: Object,
61
+ required: true
62
+ },
63
+ index: {
64
+ type: Number,
65
+ required: true
66
+ }
67
+ });
68
+ const eventCategory = computed(() => {
69
+ if (props.item.category) {
70
+ return "list.filters.news.category." + props.item.category;
71
+ } else {
72
+ return "list.filters.news.category.others";
73
+ }
74
+ });
75
+ </script>
@@ -4,6 +4,19 @@ query search($appId: ID = "", $search: String = "", $lang: String = "en") {
4
4
  items {
5
5
  firstname
6
6
  id
7
+ groups {
8
+ board
9
+ fellows
10
+ sab
11
+ sponsor
12
+ team
13
+ vintage {
14
+ name
15
+ theme
16
+ url
17
+ year
18
+ }
19
+ }
7
20
  image {
8
21
  alt
9
22
  backgroundColor
@@ -329,7 +329,7 @@
329
329
  "upcoming-events": "Upcoming events",
330
330
  "videos": "Videos",
331
331
  "view-larger-map": "View on a larger map",
332
- "vintage": "Year {0}",
332
+ "vintage": "{0} Fellow",
333
333
  "visit": "Visit us",
334
334
  "visit-the-project-website": "Visit the project website",
335
335
  "watch-the-replay": "Watch the replay",
@@ -330,7 +330,7 @@
330
330
  "upcoming-events": "Événements à venir",
331
331
  "videos": "Vidéos",
332
332
  "view-larger-map": "Afficher sur une carte plus grande",
333
- "vintage": "Année {0}",
333
+ "vintage": "Résident {0}",
334
334
  "visit": "Nous rendre visite",
335
335
  "visit-the-project-website": "Visiter le site web",
336
336
  "groups": "Catégorie",
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.105",
4
+ "version": "1.0.107",
5
5
  "name": "@paris-ias/list",
6
6
  "repository": {
7
7
  "url": "git+https://github.com/IEA-Paris/list.git",
@@ -24,7 +24,7 @@
24
24
  "@nuxtjs/apollo": "^5.0.0-alpha.14",
25
25
  "@nuxtjs/i18n": "^9.5.2",
26
26
  "@nuxtjs/mdc": "0.16.1",
27
- "@paris-ias/data": "^1.8.5",
27
+ "@paris-ias/data": "^1.8.25",
28
28
  "@pinia/nuxt": "^0.5.4",
29
29
  "@types/node": "latest",
30
30
  "@urql/exchange-execute": "2.3.1",