@paris-ias/list 1.0.11 → 1.0.14

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.
Files changed (89) hide show
  1. package/README.md +71 -51
  2. package/dist/module.d.mts +8 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +64 -0
  5. package/dist/runtime/components/events/Badges.vue +5 -7
  6. package/dist/runtime/components/events/DateTimePlace.vue +11 -13
  7. package/dist/runtime/components/events/DenseItem.vue +7 -6
  8. package/dist/runtime/components/events/ExpandedItem.vue +3 -5
  9. package/dist/runtime/components/events/ListContainer.vue +6 -6
  10. package/dist/runtime/components/events/RegisterModal.vue +4 -5
  11. package/dist/runtime/components/events/RelatedItem.vue +6 -7
  12. package/dist/runtime/components/events/RowsItem.vue +12 -11
  13. package/dist/runtime/components/events/View.vue +10 -13
  14. package/dist/runtime/components/fellowships/Badges.vue +12 -15
  15. package/dist/runtime/components/fellowships/DenseItem.vue +7 -7
  16. package/dist/runtime/components/fellowships/RegisterModal.vue +3 -2
  17. package/dist/runtime/components/fellowships/RowsItem.vue +19 -21
  18. package/dist/runtime/components/fellowships/View.vue +43 -49
  19. package/dist/runtime/components/list/atoms/FiltersMenu.vue +6 -8
  20. package/dist/runtime/components/list/atoms/SearchInput.vue +42 -50
  21. package/dist/runtime/components/list/atoms/SearchItem.vue +14 -14
  22. package/dist/runtime/components/list/atoms/SearchString.vue +6 -7
  23. package/dist/runtime/components/list/atoms/SortMenu.vue +23 -40
  24. package/dist/runtime/components/list/atoms/ViewMenu.vue +14 -22
  25. package/dist/runtime/components/list/inputs/AutoComplete.vue +9 -9
  26. package/dist/runtime/components/list/inputs/BooleanSwitch.vue +9 -9
  27. package/dist/runtime/components/list/inputs/Checkbox.vue +11 -11
  28. package/dist/runtime/components/list/inputs/Select.vue +11 -11
  29. package/dist/runtime/components/list/molecules/Filters.vue +27 -42
  30. package/dist/runtime/components/list/molecules/Header.vue +5 -7
  31. package/dist/runtime/components/list/molecules/Pagination.vue +60 -102
  32. package/dist/runtime/components/list/organisms/List.vue +28 -36
  33. package/dist/runtime/components/list/views/Dense.vue +1 -14
  34. package/dist/runtime/components/list/views/Grid.vue +3 -3
  35. package/dist/runtime/components/list/views/Rows.vue +3 -3
  36. package/dist/runtime/components/list/views/Table.vue +3 -3
  37. package/dist/runtime/components/misc/atoms/CountUp.vue +89 -144
  38. package/dist/runtime/components/misc/atoms/DateStamp.vue +42 -46
  39. package/dist/runtime/components/misc/atoms/ImageContainer.vue +14 -22
  40. package/dist/runtime/components/misc/atoms/ShareMenu.vue +9 -11
  41. package/dist/runtime/components/misc/atoms/Socials.vue +46 -52
  42. package/dist/runtime/components/misc/molecules/ChipContainer.vue +7 -11
  43. package/dist/runtime/components/misc/molecules/Related.vue +9 -11
  44. package/dist/runtime/components/misc/molecules/RelatedItems.vue +7 -9
  45. package/dist/runtime/components/misc/molecules/SearchItem.vue +2 -2
  46. package/dist/runtime/components/news/DenseItem.vue +15 -15
  47. package/dist/runtime/components/news/ExpandedItem.vue +40 -50
  48. package/dist/runtime/components/news/Header.vue +3 -5
  49. package/dist/runtime/components/news/RelatedItem.vue +6 -7
  50. package/dist/runtime/components/news/RowsItem.vue +14 -16
  51. package/dist/runtime/components/news/View.vue +9 -20
  52. package/dist/runtime/components/people/DenseItem.vue +9 -8
  53. package/dist/runtime/components/people/ExpandedItem.vue +4 -6
  54. package/dist/runtime/components/people/GroupBadges.vue +6 -8
  55. package/dist/runtime/components/people/RelatedItem.vue +6 -7
  56. package/dist/runtime/components/people/RowsItem.vue +12 -19
  57. package/dist/runtime/components/people/View.vue +7 -7
  58. package/dist/runtime/components/projects/ExpandedItem.vue +4 -6
  59. package/dist/runtime/components/projects/RelatedItem.vue +6 -7
  60. package/dist/runtime/components/projects/RowsItem.vue +21 -26
  61. package/dist/runtime/components/projects/View.vue +8 -8
  62. package/dist/runtime/components/publications/RelatedItem.vue +6 -7
  63. package/dist/runtime/components/publications/RowsItem.vue +20 -22
  64. package/dist/runtime/components/publications/View.vue +9 -15
  65. package/dist/runtime/composables/useFetchItem.d.ts +6 -0
  66. package/dist/runtime/composables/useFetchItem.js +49 -0
  67. package/dist/runtime/composables/useIcons.d.ts +1 -0
  68. package/dist/runtime/composables/useIcons.js +30 -0
  69. package/dist/runtime/composables/useUtils.d.ts +12 -0
  70. package/dist/runtime/composables/useUtils.js +47 -0
  71. package/dist/runtime/plugins/pinia.d.ts +2 -0
  72. package/dist/runtime/plugins/{pinia.ts → pinia.js} +30 -48
  73. package/dist/runtime/plugins/vuetify.d.ts +2 -0
  74. package/dist/runtime/plugins/vuetify.js +7 -7
  75. package/dist/runtime/server/tsconfig.json +3 -0
  76. package/dist/runtime/stores/factory.d.ts +1 -0
  77. package/dist/runtime/stores/{factory.ts → factory.js} +9 -9
  78. package/dist/runtime/stores/root.d.ts +34 -0
  79. package/dist/runtime/stores/root.js +227 -0
  80. package/dist/types.d.mts +3 -0
  81. package/package.json +55 -26
  82. package/dist/runtime/composables/useFetchItem.ts +0 -64
  83. package/dist/runtime/composables/useIcons.ts +0 -30
  84. package/dist/runtime/composables/useUtils.ts +0 -75
  85. package/dist/runtime/stores/root.ts +0 -353
  86. package/example/.env.example +0 -3
  87. package/example/nuxt.config.ts +0 -19
  88. package/example/pages/index.vue +0 -27
  89. package/index.ts +0 -119
@@ -0,0 +1,227 @@
1
+ import { defineStore } from "pinia";
2
+ import SEARCH from "../graphql/queries/list/search.gql";
3
+ export const useRootStore = defineStore("rootStore", {
4
+ state: () => ({
5
+ scrolled: import.meta.browser ? window.scrollY > 0 : false,
6
+ loading: false,
7
+ total: 0,
8
+ skip: 0,
9
+ page: 1,
10
+ numberOfPages: 0,
11
+ search: "",
12
+ results: {
13
+ events: {},
14
+ news: {},
15
+ people: {},
16
+ projects: {},
17
+ fellowships: {},
18
+ publications: {}
19
+ }
20
+ }),
21
+ actions: {
22
+ setLoading(value, type = "") {
23
+ const { $stores } = useNuxtApp();
24
+ this.loading = value;
25
+ if (type.length) $stores[type].loading = value;
26
+ },
27
+ setScrolled() {
28
+ if (import.meta.browser) {
29
+ this.scrolled = window.scrollY > 0;
30
+ }
31
+ },
32
+ loadRouteQuery(type) {
33
+ const { currentRoute } = useRouter();
34
+ const { $stores } = useNuxtApp();
35
+ const query = currentRoute.value.query;
36
+ if (Object.keys(query)?.length) {
37
+ Object.keys(query).forEach((filter) => {
38
+ if (Object.keys($stores[type].filters).includes(filter))
39
+ $stores[type].filters[filter].value = this[type].list.filters[filter].multiple ? JSON.parse(query[filter]) : query[filter];
40
+ });
41
+ }
42
+ console.log("query loaded");
43
+ },
44
+ setFiltersCount(type) {
45
+ const { $stores } = useNuxtApp();
46
+ let filtersCount = 0;
47
+ Object.keys($stores[type].filters).forEach((filter) => {
48
+ if ($stores[type].filters[filter]?.value?.length && typeof $stores[type].filters[filter]?.value !== "undefined") {
49
+ filtersCount++;
50
+ }
51
+ return filtersCount;
52
+ });
53
+ $stores[type].filtersCount = filtersCount;
54
+ },
55
+ setBlankFilterLoad(type) {
56
+ },
57
+ setDefaults() {
58
+ const lang = localStorage.getItem("lang");
59
+ },
60
+ updateRouteQuery(type) {
61
+ const router = useRouter();
62
+ const { $stores } = useNuxtApp();
63
+ const routeQuery = {
64
+ // Add search if it exists and is defined
65
+ ...this.search ? { search: this.search } : {},
66
+ // Add page if it's greater than 1
67
+ ...this.page > 1 ? { page: this.page.toString() } : {},
68
+ // Add filters with defined values
69
+ ...Object.entries($stores[type].filters).reduce(
70
+ (acc, [filterKey, filter]) => {
71
+ if (!$stores[type].filters[filterKey]?.value) {
72
+ return acc;
73
+ }
74
+ return {
75
+ ...acc,
76
+ ...{
77
+ [filterKey]: $stores[type].filters[filterKey]?.value
78
+ }
79
+ };
80
+ },
81
+ {}
82
+ )
83
+ };
84
+ router.replace({ query: routeQuery });
85
+ },
86
+ resetState() {
87
+ const { $stores } = useNuxtApp();
88
+ console.log("resetState");
89
+ this.search = "";
90
+ this.page = 1;
91
+ this.scrolled = false;
92
+ this.loading = false;
93
+ this.total = 0;
94
+ this.skip = 0;
95
+ this.numberOfPages = 0;
96
+ const modules = [
97
+ "events",
98
+ "news",
99
+ "people",
100
+ "projects",
101
+ "fellowships",
102
+ "publications"
103
+ ];
104
+ modules.forEach((type) => {
105
+ });
106
+ },
107
+ updateSort({ value, type }) {
108
+ const { $stores } = useNuxtApp();
109
+ $stores[type].sortBy = [value[0]];
110
+ $stores[type].sortDesc = [value[1]];
111
+ this.page = 1;
112
+ this.updateLocalStorage(type + "_sort", value.join("_"));
113
+ this.update(type);
114
+ },
115
+ updateView({ value, type }) {
116
+ const { $stores } = useNuxtApp();
117
+ $stores[type].view = {
118
+ ...$stores[type].views[value],
119
+ name: value
120
+ };
121
+ this.updateLocalStorage(type + "_view", value);
122
+ this.update(type);
123
+ },
124
+ updateLocalStorage(key, value) {
125
+ const local = JSON.parse(localStorage.getItem("PARIS_IAS")) || {};
126
+ local[key] = value;
127
+ localStorage.setItem("PARIS_IAS", JSON.stringify(local));
128
+ },
129
+ updateFilter(key, val, type) {
130
+ const { $stores } = useNuxtApp();
131
+ console.log("update filter: ", { key, val, type });
132
+ if (["online", "outside", "past"].includes(key) && val === false) {
133
+ $stores[type].filters[key].value = null;
134
+ } else {
135
+ $stores[type].filters[key].value = val;
136
+ }
137
+ this.updatePage({ page: 1, type });
138
+ },
139
+ updateItemsPerPage({ value, type }) {
140
+ const { $stores } = useNuxtApp();
141
+ this.page = 1;
142
+ $stores[types].itemsPerPage = value;
143
+ this.update(type);
144
+ },
145
+ updatePage({ page, type }) {
146
+ this.page = page;
147
+ this.update(type);
148
+ },
149
+ async updateSearch({
150
+ type = "all",
151
+ search = "",
152
+ lang = "en"
153
+ }) {
154
+ this.search = search;
155
+ this.setLoading(true);
156
+ await this.update(type, lang);
157
+ },
158
+ async update(type, lang = "en") {
159
+ const { $stores } = useNuxtApp();
160
+ this.setLoading(true);
161
+ if (type !== "all") {
162
+ $stores[type].loading = true;
163
+ }
164
+ const itemsPerPage = type === "all" ? 3 : $stores[type]?.itemsPerPage;
165
+ const filters = {};
166
+ if (type !== "all") {
167
+ for (const filter in $stores[type].filters) {
168
+ const filterValue = $stores[type].filters[filter]?.value;
169
+ if (typeof filterValue !== "undefined" && filterValue?.length) {
170
+ filters[filter] = filterValue;
171
+ }
172
+ }
173
+ }
174
+ const args = JSON.parse(
175
+ JSON.stringify({
176
+ options: {
177
+ // skip
178
+ skip: +this.page === 1 ? 0 : (+this.page - 1) * itemsPerPage,
179
+ // limit
180
+ limit: itemsPerPage,
181
+ // sort, array of keys and array of directions - to have x tie breakers if necessary
182
+ sortBy: type === "all" ? "searchScore" : $stores[type].sortBy,
183
+ sortDesc: type === "all" ? -1 : $stores[type].sortDesc > 0 ? true : false,
184
+ // search (if set)
185
+ ...this.search?.length && type !== "all" && { search: this.search },
186
+ // add the store module filters
187
+ filters
188
+ },
189
+ ...this.search?.length && type === "all" && { search: this.search },
190
+ appId: "iea",
191
+ lang
192
+ })
193
+ );
194
+ args.options.filters = JSON.stringify(args.options.filters);
195
+ let result = {};
196
+ console.log("args: ", args);
197
+ console.log(`Fetching ${type}`);
198
+ const { $queries } = useNuxtApp();
199
+ const { data, error } = await useAsyncQuery(
200
+ type === "all" ? SEARCH : $queries[type].list,
201
+ args
202
+ );
203
+ if (error.value) console.log(error.value);
204
+ const key = type === "all" ? "search" : "list" + type.charAt(0).toUpperCase() + type.slice(1);
205
+ if (type === "all") {
206
+ this.results = data?.value?.[key];
207
+ } else {
208
+ const items = data?.value?.[key]?.items ?? [];
209
+ this.total = data?.value?.[key]?.total;
210
+ result = {
211
+ ...data?.value?.[key],
212
+ items: items.map(({ id, ...rest }) => ({
213
+ ...rest,
214
+ _path: `/${id}`
215
+ }))
216
+ };
217
+ $stores[type].items = result["items"];
218
+ const lastPage = Math.ceil(result.total / itemsPerPage);
219
+ this.setFiltersCount(type);
220
+ this.setBlankFilterLoad(type);
221
+ $stores[type].numberOfPages = lastPage;
222
+ }
223
+ this.setLoading(false, type);
224
+ return true;
225
+ }
226
+ }
227
+ });
@@ -0,0 +1,3 @@
1
+ export { default } from './module.mjs'
2
+
3
+ export { type ModuleOptions } from './module.mjs'
package/package.json CHANGED
@@ -1,40 +1,69 @@
1
1
  {
2
+ "license": "AGPL-3.0-only",
3
+ "main": "./dist/module.mjs",
4
+ "version": "1.0.14",
2
5
  "name": "@paris-ias/list",
3
- "version": "1.0.11",
4
- "private": false,
5
- "type": "module",
6
- "main": "./index.ts",
7
- "files": [
8
- "example",
9
- "index.ts",
10
- "src",
11
- "lib",
12
- "dist"
13
- ],
14
- "scripts": {},
6
+ "repository": "IEA-Paris/list",
15
7
  "dependencies": {
16
- "@mdi/font": "^7.4.47",
17
- "@nuxt/content": "^2.9.0",
18
- "@nuxt/image": "^1.10.0",
19
- "@nuxtjs/mdc": "0.16.1",
20
- "@pinia/nuxt": "^0.5.5",
21
- "pinia": "^3.0.1",
22
- "sass": "^1.78.0",
23
- "vue": "^3.5.13",
24
- "vuetify": "3.8.0"
8
+ "@nuxt/kit": "^3.16.2"
25
9
  },
10
+ "description": "Paris IAS List Module",
26
11
  "devDependencies": {
12
+ "@mdi/font": "^7.4.47",
13
+ "@nuxt/content": "^2.9.0",
14
+ "@nuxt/devtools": "^2.3.2",
15
+ "@nuxt/eslint": "1.3.0",
16
+ "@nuxt/eslint-config": "^1.3.0",
17
+ "@nuxt/image": "1.10.0",
18
+ "@nuxt/module-builder": "^1.0.0",
19
+ "@nuxt/schema": "^3.16.2",
20
+ "@nuxt/test-utils": "^3.17.2",
27
21
  "@nuxtjs/apollo": "^5.0.0-alpha.14",
28
22
  "@nuxtjs/i18n": "^9.5.2",
23
+ "@nuxtjs/mdc": "0.16.1",
29
24
  "@paris-ias/data": "^1.8.0",
30
- "@types/node": "^20.0.0",
25
+ "@pinia/nuxt": "^0.10.1",
26
+ "@types/node": "latest",
31
27
  "@vueuse/core": "^13.0.0",
28
+ "changelogen": "^0.6.1",
29
+ "eslint": "^9.24.0",
32
30
  "graphql-tag": "^2.12.6",
33
31
  "nuxt": "^3.16.2",
34
- "typescript": "^5.6.3",
35
- "vite-plugin-graphql-loader": "^4.0.4"
32
+ "pinia": "^3.0.1",
33
+ "sass": "^1.78.0",
34
+ "typescript": "~5.8.3",
35
+ "vite-plugin-graphql-loader": "^4.0.4",
36
+ "vitest": "^3.1.1",
37
+ "vue": "^3.5.13",
38
+ "vue-tsc": "^2.2.8",
39
+ "vuetify": "3.8.0"
36
40
  },
37
- "peerDependencies": {
38
- "nuxt": "^3.0.0"
41
+ "exports": {
42
+ ".": {
43
+ "import": "./dist/module.mjs",
44
+ "types": "./dist/types.d.mts"
45
+ }
46
+ },
47
+ "files": [
48
+ "dist"
49
+ ],
50
+ "scripts": {
51
+ "dev": "nuxi dev playground",
52
+ "dev:build": "nuxi build playground",
53
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
54
+ "lint": "eslint .",
55
+ "prepack": "nuxt-module-build build",
56
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
57
+ "test": "vitest run",
58
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
59
+ "test:watch": "vitest watch"
60
+ },
61
+ "type": "module",
62
+ "typesVersions": {
63
+ "*": {
64
+ ".": [
65
+ "./dist/types.d.mts"
66
+ ]
67
+ }
39
68
  }
40
69
  }
@@ -1,64 +0,0 @@
1
- import { useRoute } from "vue-router"
2
- export const useFetchItem = () => {
3
- const fetchItem = async <T>(payload: {
4
- query: string
5
- key: string
6
- }): Promise<T> => {
7
- try {
8
- const { locale } = useI18n()
9
- const route = useRoute()
10
-
11
- const variables = {
12
- itemId: route.params.slug?.toString().trim(),
13
- appId: "iea",
14
- lang: locale.value,
15
- }
16
- const { data, error } = await useAsyncQuery(payload.query, variables)
17
- /* console.log("variables: ", variables) */
18
-
19
- if (error.value) {
20
- console.error("GraphQL error:", error.value)
21
- throw error.value
22
- }
23
-
24
- const item = data?.value[payload.key]
25
- /* console.log("item: ", item) */
26
-
27
- if (!item) {
28
- throw createError({
29
- statusCode: 404,
30
- message: "Item not found in response",
31
- })
32
- }
33
- // Update the slug in the i18n params
34
- // for people, the slug is the same in both languages
35
- // for other items, the slug is different in each language
36
- const setI18nParams = useSetI18nParams()
37
- if (!route.name.includes("people")) {
38
- /* console.log("update params") */
39
- setI18nParams({
40
- en: { slug: item.slug.en },
41
- fr: { slug: item.slug.fr },
42
- })
43
- } else {
44
- // for people, the slug is the same in both languages
45
- setI18nParams({
46
- en: { slug: item.slug },
47
- fr: { slug: item.slug },
48
- })
49
- }
50
- return item as T
51
- } catch (error) {
52
- console.error("Error fetching item:", error)
53
- throw createError({
54
- statusCode: 404,
55
- message: "Item not found",
56
- cause: error,
57
- })
58
- }
59
- }
60
-
61
- return {
62
- fetchItem,
63
- }
64
- }
@@ -1,30 +0,0 @@
1
- export default function getFileIcon(fileName: string): string {
2
- console.log("fileName: ", fileName)
3
- const fileExtension = fileName.split(".").pop()
4
- console.log("fileExtension: ", fileExtension)
5
- switch (fileExtension) {
6
- case "pdf":
7
- return "mdi-file-pdf-box"
8
- case "doc":
9
- case "docx":
10
- return "mdi-file-word"
11
- case "xls":
12
- case "xlsx":
13
- return "mdi-file-excel"
14
- case "ppt":
15
- case "pptx":
16
- return "mdi-file-powerpoint"
17
- case "jpg":
18
- case "jpeg":
19
- case "png":
20
- case "gif":
21
- return "mdi-file-image"
22
- case "zip":
23
- case "rar":
24
- return "mdi-folder-zip"
25
- case "txt":
26
- return "mdi-file-document"
27
- default:
28
- return "mdi-file"
29
- }
30
- }
@@ -1,75 +0,0 @@
1
- export const formatDate = (dateStr: string, locale: string): string => {
2
- const date = new Date(dateStr)
3
- return date.toLocaleDateString(locale, {
4
- weekday: "long",
5
- year: "numeric",
6
- month: "long",
7
- day: "numeric",
8
- })
9
- }
10
-
11
- export const getLocalizedDate = (dateIso: string): string => {
12
- const { $i18n } = useNuxtApp()
13
- return new Date(dateIso).toLocaleDateString(
14
- $i18n.localeProperties.value.language,
15
- {
16
- weekday: "long",
17
- year: "numeric",
18
- month: "long",
19
- day: "numeric",
20
- }
21
- )
22
- }
23
-
24
- export const getDetailedFormatedDate = (
25
- dateStr: string,
26
- locale: string
27
- ): {
28
- day: number
29
- month: string
30
- year: number
31
- hours: number
32
- minutes: number
33
- } => {
34
- const date = new Date(dateStr)
35
-
36
- return {
37
- day: date.getDate(),
38
- month: date.toLocaleString(locale, { month: "long" }),
39
- year: date.getFullYear(),
40
- hours: date.getUTCHours(),
41
- minutes: date.getMinutes(),
42
- }
43
- }
44
-
45
- export const capitalize = (value: string, multiple?: boolean) =>
46
- multiple
47
- ? value.replace(/(?:^|[\s'-])\S/g, (a) => a.toUpperCase())
48
- : value && value.charAt(0).toUpperCase() + value.slice(1)
49
-
50
- export const slugify = (str: string) => {
51
- str = str.replace(/^\s+|\s+$/g, "").trim() // trim
52
- str = str.toLowerCase()
53
-
54
- // remove accents, swap ñ for n, etc
55
- const from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;"
56
- const to = "aaaaeeeeiiiioooouuuunc------"
57
- for (let i = 0, l = from.length; i < l; i++) {
58
- str = str.replace(new RegExp(from.charAt(i), "g"), to.charAt(i))
59
- }
60
-
61
- str = str
62
- .replace(/[^a-z0-9 -]/g, "") // remove invalid chars
63
- .replace(/\s+/g, "-") // collapse whitespace and replace by -
64
- .replace(/-+/g, "-") // collapse dashes
65
-
66
- return str
67
- }
68
-
69
- export const formatDateValue = (
70
- date: string | Date,
71
- locale: string
72
- ): string => {
73
- const formattedDate = new Date(date)
74
- return formattedDate.toLocaleDateString(locale)
75
- }