@paris-ias/list 1.2.1 → 1.3.0
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/fellowships/View.vue +29 -41
- package/dist/runtime/components/list/molecules/Filters.vue +24 -21
- package/dist/runtime/components/misc/molecules/DisciplinesTags.vue +79 -0
- package/dist/runtime/components/people/View.vue +25 -32
- package/dist/runtime/components/projects/View.vue +10 -2
- package/dist/runtime/components/publications/View.vue +8 -2
- package/dist/runtime/translations/en.json +6 -0
- package/dist/runtime/translations/fr.json +6 -0
- package/package.json +2 -2
package/dist/module.json
CHANGED
|
@@ -49,12 +49,15 @@
|
|
|
49
49
|
'list.filters.fellowships.fellowshipType.' +
|
|
50
50
|
item.fellowshipType,
|
|
51
51
|
),
|
|
52
|
-
...(props.item && props.item.disciplines
|
|
53
|
-
? props.item.disciplines.map((discipline) => discipline.name)
|
|
54
|
-
: []),
|
|
55
52
|
]"
|
|
56
53
|
class="mt-2"
|
|
57
54
|
/>
|
|
55
|
+
<!-- DISCIPLINES -->
|
|
56
|
+
<MiscMoleculesDisciplinesTags
|
|
57
|
+
:disciplines="item.disciplines"
|
|
58
|
+
justify="center"
|
|
59
|
+
class="mt-4"
|
|
60
|
+
/>
|
|
58
61
|
<div class="mt-5">
|
|
59
62
|
<FellowshipsBadges :item="item" :view="view" :loading="loading" />
|
|
60
63
|
</div>
|
|
@@ -152,58 +155,43 @@
|
|
|
152
155
|
|
|
153
156
|
<script setup>
|
|
154
157
|
import { useDisplay } from "vuetify"
|
|
155
|
-
import { ref } from "#imports"
|
|
158
|
+
import { computed, ref } from "#imports"
|
|
156
159
|
const { name } = useDisplay()
|
|
157
160
|
const accordeon = ref(-1)
|
|
158
161
|
const props = defineProps({
|
|
162
|
+
// null while the resource item is loading (see useI18nResourceItem)
|
|
159
163
|
item: {
|
|
160
164
|
type: Object,
|
|
161
|
-
|
|
165
|
+
default: null,
|
|
162
166
|
},
|
|
163
167
|
loading: {
|
|
164
168
|
type: Boolean,
|
|
165
169
|
default: false,
|
|
166
|
-
required: true,
|
|
167
170
|
},
|
|
168
171
|
})
|
|
169
172
|
|
|
170
173
|
const view = ref(true)
|
|
171
174
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
housing: props.item?.fellowshipDetails?.housing,
|
|
193
|
-
}),
|
|
194
|
-
...(props.item?.fellowshipDetails?.meals && {
|
|
195
|
-
meals: props.item?.fellowshipDetails?.meals,
|
|
196
|
-
}),
|
|
197
|
-
...(props.item?.fellowshipDetails?.applicationMaterials && {
|
|
198
|
-
applicationMaterials: props.item?.fellowshipDetails?.applicationMaterials,
|
|
199
|
-
}),
|
|
200
|
-
...(props.item?.fellowshipDetails?.selectionProcess && {
|
|
201
|
-
selectionProcess: props.item?.fellowshipDetails?.selectionProcess,
|
|
202
|
-
}),
|
|
203
|
-
...(props.item?.fellowshipDetails?.researchProcess && {
|
|
204
|
-
researchProcess: props.item?.fellowshipDetails?.researchProcess,
|
|
205
|
-
}),
|
|
206
|
-
}
|
|
175
|
+
// computed (not a one-shot setup value) so it picks up `item` once it loads in
|
|
176
|
+
const renderedDetails = computed(() => {
|
|
177
|
+
const d = props.item?.fellowshipDetails
|
|
178
|
+
if (!d) return {}
|
|
179
|
+
return {
|
|
180
|
+
...(d.type && { type: d.type }),
|
|
181
|
+
...(d.fundingPeriod && { fundingPeriod: d.fundingPeriod }),
|
|
182
|
+
...(d.profile && { profile: d.profile }),
|
|
183
|
+
...(d.tasks && { tasks: d.tasks }),
|
|
184
|
+
...(d.location && { location: d.location }),
|
|
185
|
+
...(d.funding && { funding: d.funding }),
|
|
186
|
+
...(d.housing && { housing: d.housing }),
|
|
187
|
+
...(d.meals && { meals: d.meals }),
|
|
188
|
+
...(d.applicationMaterials && {
|
|
189
|
+
applicationMaterials: d.applicationMaterials,
|
|
190
|
+
}),
|
|
191
|
+
...(d.selectionProcess && { selectionProcess: d.selectionProcess }),
|
|
192
|
+
...(d.researchProcess && { researchProcess: d.researchProcess }),
|
|
193
|
+
}
|
|
194
|
+
})
|
|
207
195
|
</script>
|
|
208
196
|
|
|
209
197
|
<style lang="scss" scoped></style>
|
|
@@ -62,28 +62,31 @@ const getItems = (name) => {
|
|
|
62
62
|
return []
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// Disciplines and thematics are shared enums used across most list types.
|
|
66
|
+
// They live in their own top-level i18n namespace (list.filters.disciplines
|
|
67
|
+
// / list.filters.thematics) and are resolved from there for every type,
|
|
68
|
+
// independently of filters.json, to avoid duplicating them per type.
|
|
69
|
+
if (["disciplines", "thematics"].includes(name)) {
|
|
70
|
+
return Object.keys(messages.value[locale.value].list.filters?.[name])
|
|
71
|
+
.filter((key) => key !== "label")
|
|
72
|
+
.map((item) => ({
|
|
73
|
+
title: i18n.t(`list.filters.${name}.${item}`),
|
|
74
|
+
value: item,
|
|
75
|
+
}))
|
|
76
|
+
.sort((a, b) => a.title.localeCompare(b.title))
|
|
77
|
+
}
|
|
78
|
+
|
|
65
79
|
if ($filters?.[props.type]?.[name]) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return $filters[props.type][name]
|
|
77
|
-
.filter((key) => key !== "label")
|
|
78
|
-
.map((item) => ({
|
|
79
|
-
title: i18n.t(
|
|
80
|
-
props.type === "people" && name === "vintage"
|
|
81
|
-
? item
|
|
82
|
-
: `list.filters.${props.type}.${name}.${item}`,
|
|
83
|
-
),
|
|
84
|
-
value: item,
|
|
85
|
-
}))
|
|
86
|
-
}
|
|
80
|
+
return $filters[props.type][name]
|
|
81
|
+
.filter((key) => key !== "label")
|
|
82
|
+
.map((item) => ({
|
|
83
|
+
title: i18n.t(
|
|
84
|
+
props.type === "people" && name === "vintage"
|
|
85
|
+
? item
|
|
86
|
+
: `list.filters.${props.type}.${name}.${item}`,
|
|
87
|
+
),
|
|
88
|
+
value: item,
|
|
89
|
+
}))
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
if (!messages.value[locale.value].list.filters[props.type]?.[name]) {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-skeleton-loader
|
|
3
|
+
v-if="loading"
|
|
4
|
+
type="chip@3"
|
|
5
|
+
class="discipline-skeleton mt-2"
|
|
6
|
+
/>
|
|
7
|
+
<div
|
|
8
|
+
v-else-if="disciplines.length"
|
|
9
|
+
class="d-flex flex-wrap"
|
|
10
|
+
:class="justify === 'center' ? 'justify-center' : ''"
|
|
11
|
+
style="gap: 6px"
|
|
12
|
+
>
|
|
13
|
+
<v-chip
|
|
14
|
+
v-for="(d, i) in shownDisciplines"
|
|
15
|
+
:key="d + i"
|
|
16
|
+
size="small"
|
|
17
|
+
tile
|
|
18
|
+
variant="flat"
|
|
19
|
+
color="grey-lighten-3"
|
|
20
|
+
class="discipline-chip"
|
|
21
|
+
>
|
|
22
|
+
{{ disciplineLabel(d) }}
|
|
23
|
+
</v-chip>
|
|
24
|
+
<v-chip
|
|
25
|
+
v-if="extraDisciplines"
|
|
26
|
+
size="small"
|
|
27
|
+
variant="flat"
|
|
28
|
+
tile
|
|
29
|
+
color="grey-lighten-3"
|
|
30
|
+
class="discipline-chip"
|
|
31
|
+
>
|
|
32
|
+
+{{ extraDisciplines }}
|
|
33
|
+
</v-chip>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup>
|
|
38
|
+
import { computed, useI18n } from "#imports"
|
|
39
|
+
|
|
40
|
+
const { t } = useI18n()
|
|
41
|
+
|
|
42
|
+
const props = defineProps({
|
|
43
|
+
// scalar enum array (e.g. item.disciplines)
|
|
44
|
+
disciplines: {
|
|
45
|
+
type: Array,
|
|
46
|
+
default: () => [],
|
|
47
|
+
},
|
|
48
|
+
loading: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
52
|
+
// cap the number of chips; 0 = show all (used by detail views)
|
|
53
|
+
max: {
|
|
54
|
+
type: Number,
|
|
55
|
+
default: 0,
|
|
56
|
+
},
|
|
57
|
+
// 'start' (dense list) | 'center' (detail views)
|
|
58
|
+
justify: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: "start",
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// normalise to an array regardless of what the caller passes
|
|
65
|
+
const disciplines = computed(() =>
|
|
66
|
+
Array.isArray(props.disciplines) ? props.disciplines : [],
|
|
67
|
+
)
|
|
68
|
+
const shownDisciplines = computed(() =>
|
|
69
|
+
props.max > 0 ? disciplines.value.slice(0, props.max) : disciplines.value,
|
|
70
|
+
)
|
|
71
|
+
const extraDisciplines = computed(() =>
|
|
72
|
+
props.max > 0 ? Math.max(0, disciplines.value.length - props.max) : 0,
|
|
73
|
+
)
|
|
74
|
+
const disciplineLabel = (d) => t("list.filters.disciplines." + d)
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style scoped>
|
|
78
|
+
.discipline-chip{border-radius:6px;color:rgba(0,0,0,.78);font-weight:500}.discipline-skeleton :deep(.v-skeleton-loader__chip){margin:0 6px 0 0}
|
|
79
|
+
</style>
|
|
@@ -73,37 +73,35 @@
|
|
|
73
73
|
<div class="mt-6 align-self-center">
|
|
74
74
|
<PeopleBadges v-if="item && item.groups" :item="item" />
|
|
75
75
|
</div>
|
|
76
|
-
|
|
76
|
+
<!-- DIVIDERS -->
|
|
77
|
+
<v-responsive class="mx-auto my-6" width="120">
|
|
78
|
+
<v-divider class="mb-1" />
|
|
79
|
+
<v-divider />
|
|
80
|
+
</v-responsive>
|
|
77
81
|
<!-- FELLOWSHIP -->
|
|
78
|
-
<div
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<!-- DISCIPLINES -->
|
|
82
|
+
<div
|
|
83
|
+
v-if="fellowshipProjectName || fellowTheme || fellowDates"
|
|
84
|
+
class=""
|
|
85
|
+
>
|
|
84
86
|
<div
|
|
85
|
-
v-if="
|
|
86
|
-
class="
|
|
87
|
-
style="gap: 6px"
|
|
87
|
+
v-if="fellowshipProjectName"
|
|
88
|
+
class="text-h6 font-weight-regular"
|
|
88
89
|
>
|
|
89
|
-
|
|
90
|
-
v-for="(d, i) in disciplines"
|
|
91
|
-
:key="d + i"
|
|
92
|
-
size="small"
|
|
93
|
-
variant="flat"
|
|
94
|
-
tile
|
|
95
|
-
color="grey-lighten-3"
|
|
96
|
-
class="discipline-chip"
|
|
97
|
-
>
|
|
98
|
-
{{ disciplineLabel(d) }}
|
|
99
|
-
</v-chip>
|
|
90
|
+
{{ fellowshipProjectName }}
|
|
100
91
|
</div>
|
|
101
|
-
|
|
92
|
+
|
|
93
|
+
<!-- DISCIPLINES -->
|
|
94
|
+
<MiscMoleculesDisciplinesTags
|
|
95
|
+
:disciplines="item.disciplines"
|
|
96
|
+
justify="center"
|
|
97
|
+
class="mt-4"
|
|
98
|
+
/>
|
|
99
|
+
<div v-if="fellowTheme" class="text-body-1 my-3 font-italic">
|
|
102
100
|
{{ fellowTheme }}
|
|
103
101
|
</div>
|
|
104
102
|
<div
|
|
105
103
|
v-if="fellowDates"
|
|
106
|
-
class="text-body-2
|
|
104
|
+
class="text-body-2 my-3 text-medium-emphasis"
|
|
107
105
|
>
|
|
108
106
|
{{ fellowDates }}
|
|
109
107
|
</div>
|
|
@@ -217,22 +215,17 @@ const { t, locale } = useI18n()
|
|
|
217
215
|
const { $stores } = useNuxtApp()
|
|
218
216
|
const { name, mdAndUp } = useDisplay()
|
|
219
217
|
const props = defineProps({
|
|
220
|
-
|
|
218
|
+
// null while the resource item is loading (see useI18nResourceItem)
|
|
219
|
+
item: { type: Object, default: null },
|
|
221
220
|
loading: { type: Boolean, default: false },
|
|
222
221
|
})
|
|
223
222
|
$stores.people.loading = false
|
|
224
223
|
|
|
225
|
-
// disciplines: scalar enum array → translated labels
|
|
226
|
-
const disciplines = computed(() =>
|
|
227
|
-
Array.isArray(props.item?.disciplines) ? props.item.disciplines : [],
|
|
228
|
-
)
|
|
229
|
-
const disciplineLabel = (d) => t("list.filters.disciplines." + d)
|
|
230
|
-
|
|
231
224
|
// latest is a union Vintage | Position; the fellowship program lives on the
|
|
232
225
|
// Vintage branch (name = program name, theme = fellowship theme) and carries the
|
|
233
226
|
// arrival/departure dates (start/stop). Guard by field presence.
|
|
234
227
|
const latest = computed(() => props.item?.latest ?? null)
|
|
235
|
-
const
|
|
228
|
+
const fellowshipProjectName = computed(() => latest.value?.name ?? null)
|
|
236
229
|
const fellowTheme = computed(() => latest.value?.theme ?? null)
|
|
237
230
|
|
|
238
231
|
// "present" = currently in residence/post: started on or before today and not
|
|
@@ -259,5 +252,5 @@ const fellowDates = computed(() => {
|
|
|
259
252
|
</script>
|
|
260
253
|
|
|
261
254
|
<style scoped>
|
|
262
|
-
.
|
|
255
|
+
.present-pill{align-items:center;background-color:rgba(0,0,0,.06);border-radius:999px;color:rgba(0,0,0,.7);display:inline-flex;font-size:.6875rem;font-weight:500;gap:5px;letter-spacing:.04em;line-height:1;padding:4px 10px;text-transform:uppercase}.present-dot{background-color:#4caf50;border-radius:50%;height:6px;width:6px}
|
|
263
256
|
</style>
|
|
@@ -45,6 +45,13 @@
|
|
|
45
45
|
>
|
|
46
46
|
<MDC v-if="item && item.subtitle" :value="item.subtitle" />
|
|
47
47
|
</div>
|
|
48
|
+
<!-- DISCIPLINES -->
|
|
49
|
+
<MiscMoleculesDisciplinesTags
|
|
50
|
+
v-if="item"
|
|
51
|
+
:disciplines="item.disciplines"
|
|
52
|
+
justify="center"
|
|
53
|
+
class="mt-4"
|
|
54
|
+
/>
|
|
48
55
|
<MiscMoleculesChipContainer
|
|
49
56
|
v-if="item && item.tags"
|
|
50
57
|
:items="item.tags"
|
|
@@ -120,13 +127,14 @@ import { useNuxtApp } from "#imports"
|
|
|
120
127
|
const { $stores } = useNuxtApp()
|
|
121
128
|
const { name } = useDisplay()
|
|
122
129
|
const props = defineProps({
|
|
130
|
+
// null while the resource item is loading (see useI18nResourceItem)
|
|
123
131
|
item: {
|
|
124
132
|
type: Object,
|
|
125
|
-
|
|
133
|
+
default: null,
|
|
126
134
|
},
|
|
127
135
|
loading: {
|
|
128
136
|
type: Boolean,
|
|
129
|
-
|
|
137
|
+
default: false,
|
|
130
138
|
},
|
|
131
139
|
})
|
|
132
140
|
</script>
|
|
@@ -40,6 +40,12 @@
|
|
|
40
40
|
<div class="overline my-2">
|
|
41
41
|
{{ formatDateValue(item.date, locale) }}
|
|
42
42
|
</div>
|
|
43
|
+
<!-- DISCIPLINES -->
|
|
44
|
+
<MiscMoleculesDisciplinesTags
|
|
45
|
+
:disciplines="item.disciplines"
|
|
46
|
+
justify="center"
|
|
47
|
+
class="mt-4"
|
|
48
|
+
/>
|
|
43
49
|
<MiscMoleculesChipContainer
|
|
44
50
|
v-if="item.tags && item.tags.length"
|
|
45
51
|
:items="item.tags"
|
|
@@ -119,13 +125,13 @@ const { $stores } = useNuxtApp()
|
|
|
119
125
|
const { name } = useDisplay()
|
|
120
126
|
const { locale } = useI18n()
|
|
121
127
|
const props = defineProps({
|
|
128
|
+
// null while the resource item is loading (see useI18nResourceItem)
|
|
122
129
|
item: {
|
|
123
130
|
type: Object,
|
|
124
|
-
|
|
131
|
+
default: null,
|
|
125
132
|
},
|
|
126
133
|
loading: {
|
|
127
134
|
type: Boolean,
|
|
128
|
-
required: false,
|
|
129
135
|
default: false,
|
|
130
136
|
},
|
|
131
137
|
})
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"license": "AGPL-3.0-only",
|
|
3
3
|
"main": "./dist/module.mjs",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0",
|
|
5
5
|
"name": "@paris-ias/list",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "git+https://github.com/IEA-Paris/list.git",
|
|
8
8
|
"type": "git"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@paris-ias/trees": "^2.2.
|
|
11
|
+
"@paris-ias/trees": "^2.2.17"
|
|
12
12
|
},
|
|
13
13
|
"description": "Paris IAS List Module",
|
|
14
14
|
"peerDependencies": {
|