@paris-ias/list 1.0.17 → 1.0.19

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 (31) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/events/RowsItem.vue +4 -1
  3. package/dist/runtime/components/fellowships/Badges.vue +2 -1
  4. package/dist/runtime/components/list/atoms/SearchInput.vue +9 -5
  5. package/dist/runtime/components/list/atoms/SearchString.vue +15 -11
  6. package/dist/runtime/components/list/atoms/SortMenu.vue +5 -4
  7. package/dist/runtime/components/list/atoms/ViewMenu.vue +5 -4
  8. package/dist/runtime/components/list/inputs/AutoComplete.vue +1 -0
  9. package/dist/runtime/components/list/inputs/BooleanSwitch.vue +2 -0
  10. package/dist/runtime/components/list/inputs/Checkbox.vue +2 -3
  11. package/dist/runtime/components/list/inputs/Select.vue +2 -0
  12. package/dist/runtime/components/list/molecules/Filters.vue +6 -4
  13. package/dist/runtime/components/list/molecules/Pagination.vue +2 -3
  14. package/dist/runtime/components/list/organisms/List.vue +2 -0
  15. package/dist/runtime/components/misc/atoms/DateStamp.vue +2 -0
  16. package/dist/runtime/components/misc/atoms/ImageContainer.vue +5 -4
  17. package/dist/runtime/components/misc/molecules/Related.vue +1 -0
  18. package/dist/runtime/components/news/DenseItem.vue +5 -3
  19. package/dist/runtime/components/news/RowsItem.vue +12 -10
  20. package/dist/runtime/components/news/View.vue +7 -6
  21. package/dist/runtime/components/people/DenseItem.vue +1 -0
  22. package/dist/runtime/components/people/GroupBadges.vue +4 -3
  23. package/dist/runtime/components/people/RowsItem.vue +1 -0
  24. package/dist/runtime/components/people/View.vue +2 -1
  25. package/dist/runtime/components/projects/View.vue +1 -0
  26. package/dist/runtime/components/publications/RowsItem.vue +5 -3
  27. package/dist/runtime/components/publications/View.vue +1 -0
  28. package/dist/runtime/composables/useUtils.js +1 -0
  29. package/dist/runtime/stores/root.js +1 -0
  30. package/package.json +1 -1
  31. package/dist/runtime/components/misc/atoms/CountUp.vue +0 -143
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.17",
4
+ "version": "1.0.19",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.0",
7
7
  "unbuild": "3.5.0"
@@ -77,7 +77,9 @@
77
77
  "
78
78
  />
79
79
 
80
- <div v-else><EventsBadges :item="item" /></div>
80
+ <div v-else>
81
+ <EventsBadges :item="item" />
82
+ </div>
81
83
  </v-col>
82
84
  </v-row>
83
85
  </v-col>
@@ -97,6 +99,7 @@
97
99
  <script setup>
98
100
  import { useDisplay } from "vuetify";
99
101
  import { useRootStore } from "../../stores/root";
102
+ import { useNuxtApp, useI18n, useLocalePath } from "#imports";
100
103
  const { locale } = useI18n();
101
104
  const { name, mdAndDown, lgAndUp } = useDisplay();
102
105
  const localePath = useLocalePath();
@@ -13,7 +13,7 @@
13
13
  />
14
14
 
15
15
  <div v-else-if="registrationStatus === 2" class="my-2 text-overline">
16
- <v-icon class="text-grey" size="x-large"> mdi-circle-medium</v-icon>
16
+ <v-icon class="text-grey" size="x-large"> mdi-circle-medium </v-icon>
17
17
  {{
18
18
  $t("applications-closed-since-0", [
19
19
  getLocalizedDate(item.applicationStop),
@@ -23,6 +23,7 @@
23
23
  </template>
24
24
 
25
25
  <script setup>
26
+ import { computed } from "vue";
26
27
  const props = defineProps({
27
28
  item: { type: Object, required: true },
28
29
  view: { type: Boolean, required: false, default: false }
@@ -19,8 +19,8 @@
19
19
  <div class="searchLabel">
20
20
  {{ $t("list.search-type", [$t(type)]) }}
21
21
  </div>
22
- </template></v-text-field
23
- >
22
+ </template>
23
+ </v-text-field>
24
24
  <v-expand-transition v-if="type === 'all'">
25
25
  <v-list
26
26
  v-show="search.length"
@@ -36,8 +36,9 @@
36
36
  <v-list-subheader
37
37
  v-if="item.type && item.type === 'subheader'"
38
38
  :key="'subheader-' + index"
39
- >{{ item.name }}</v-list-subheader
40
39
  >
40
+ {{ item.name }}
41
+ </v-list-subheader>
41
42
  <div
42
43
  v-else-if="item.type && item.type === 'no-result'"
43
44
  :key="'no-result-' + index"
@@ -57,14 +58,17 @@
57
58
  :item
58
59
  :type="item.type"
59
60
  />
60
- </template> </v-list
61
- ></v-expand-transition>
61
+ </template>
62
+ </v-list>
63
+ </v-expand-transition>
62
64
  </div>
63
65
  </template>
64
66
 
65
67
  <script setup>
66
68
  import { useDebounceFn } from "@vueuse/core";
69
+ import { computed } from "vue";
67
70
  import { useRootStore } from "../../../stores/root";
71
+ import { useNuxtApp, useI18n } from "#imports";
68
72
  const { locale, t } = useI18n();
69
73
  const rootStore = useRootStore();
70
74
  const { $stores } = useNuxtApp();
@@ -32,7 +32,8 @@
32
32
  !(!$stores[type].search || $stores[type].search.length === 0) &&
33
33
  $stores[type].filtersCount === 0
34
34
  "
35
- >{{
35
+ >
36
+ {{
36
37
  feminine
37
38
  ? $t(
38
39
  "list.0-items-found-searching-for-f",
@@ -60,15 +61,16 @@
60
61
  ],
61
62
  $stores[type].total
62
63
  )
63
- }}</template
64
- >
64
+ }}
65
+ </template>
65
66
  <!-- with X filters -->
66
67
  <template
67
68
  v-else-if="
68
69
  (!$stores[type].search || $stores[type].search.length === 0) &&
69
70
  $stores[type][props.type].filtersCount > 0
70
71
  "
71
- >{{
72
+ >
73
+ {{
72
74
  feminine
73
75
  ? $t(
74
76
  "list.0-items-found-with-1-filter-f",
@@ -98,8 +100,8 @@
98
100
  ],
99
101
  $stores[type].total
100
102
  )
101
- }}</template
102
- >
103
+ }}
104
+ </template>
103
105
  <!-- searching for "XXX" with Y filters -->
104
106
  <template
105
107
  v-else-if="
@@ -107,7 +109,8 @@
107
109
  $stores[type].search.length &&
108
110
  $stores[type].filtersCount > 0
109
111
  "
110
- >{{
112
+ >
113
+ {{
111
114
  feminine
112
115
  ? $t(
113
116
  "list.0-items-found-searching-for-with-1-filter-f",
@@ -131,8 +134,8 @@
131
134
  ],
132
135
  $stores[type].total
133
136
  )
134
- }}</template
135
- >
137
+ }}
138
+ </template>
136
139
  <template v-if="$stores[type].numberOfPages > 1">
137
140
  <!-- // Page X of Y -->
138
141
  {{
@@ -140,8 +143,8 @@
140
143
  $stores[type].page || 1,
141
144
  $stores[type].numberOfPages || 1,
142
145
  ])
143
- }}</template
144
- >
146
+ }}
147
+ </template>
145
148
  <!-- X items per page -->
146
149
  <!-- displayed by X -->
147
150
  <!-- and sorted by X -->
@@ -149,6 +152,7 @@
149
152
  </template>
150
153
 
151
154
  <script setup>
155
+ import { useNuxtApp } from "#imports";
152
156
  const { $stores } = useNuxtApp();
153
157
  const props = defineProps({
154
158
  type: {
@@ -36,16 +36,17 @@
36
36
  <v-icon>mdi-{{ item.icon }}</v-icon>
37
37
  </template>
38
38
  <v-list-item-title>{{ $t("list." + item.text) }}</v-list-item-title>
39
- </v-list-item></template
40
- >
39
+ </v-list-item>
40
+ </template>
41
41
  </v-list>
42
42
  </v-menu>
43
43
  </template>
44
44
 
45
45
  <script setup>
46
- import { useRootStore } from "../../../stores/root";
47
- import { mergeProps } from "vue";
46
+ import { mergeProps, computed } from "vue";
48
47
  import { useDisplay } from "vuetify";
48
+ import { useRootStore } from "../../../stores/root";
49
+ import { useNuxtApp } from "#imports";
49
50
  const { $stores } = useNuxtApp();
50
51
  const { xs: isXsDisplay } = useDisplay();
51
52
  const rootStore = useRootStore();
@@ -31,18 +31,19 @@
31
31
  <template #prepend>
32
32
  <v-icon>mdi-{{ value.icon }}</v-icon>
33
33
  </template>
34
- <v-list-item-title>{{
35
- $t("list." + (value.name || key))
36
- }}</v-list-item-title>
34
+ <v-list-item-title>
35
+ {{ $t("list." + (value.name || key)) }}
36
+ </v-list-item-title>
37
37
  </v-list-item>
38
38
  </v-list>
39
39
  </v-menu>
40
40
  </template>
41
41
 
42
42
  <script setup>
43
- import { useRootStore } from "../../../stores/root";
44
43
  import { mergeProps } from "vue";
45
44
  import { useDisplay } from "vuetify";
45
+ import { useRootStore } from "../../../stores/root";
46
+ import { useNuxtApp } from "#imports";
46
47
  const { $stores } = useNuxtApp();
47
48
  const props = defineProps({
48
49
  type: {
@@ -8,6 +8,7 @@
8
8
 
9
9
  <script setup>
10
10
  import { useRootStore } from "../../../stores/root";
11
+ import { useNuxtApp } from "#imports";
11
12
  const rootStore = useRootStore();
12
13
  const { $stores } = useNuxtApp();
13
14
  const props = defineProps(["type", "items", "name"]);
@@ -3,7 +3,9 @@
3
3
  </template>
4
4
 
5
5
  <script setup>
6
+ import { computed } from "vue";
6
7
  import { useRootStore } from "../../../stores/root";
8
+ import { useNuxtApp } from "#imports";
7
9
  const rootStore = useRootStore();
8
10
  const props = defineProps(["type", "items", "name"]);
9
11
  const { $stores } = useNuxtApp();
@@ -3,7 +3,9 @@
3
3
  </template>
4
4
 
5
5
  <script setup>
6
+ import { computed } from "vue";
6
7
  import { useRootStore } from "../../../stores/root";
8
+ import { useNuxtApp } from "#imports";
7
9
  const rootStore = useRootStore();
8
10
  const props = defineProps(["type", "items", "name"]);
9
11
  const { $stores } = useNuxtApp();
@@ -15,7 +17,4 @@ const val = computed({
15
17
  rootStore.updateFilter(props.name, value, props.type);
16
18
  }
17
19
  });
18
- onMounted(() => {
19
- console.log(props.data);
20
- });
21
20
  </script>
@@ -7,7 +7,9 @@
7
7
  </template>
8
8
 
9
9
  <script setup>
10
+ import { computed, onMounted } from "vue";
10
11
  import { useRootStore } from "../../../stores/root";
12
+ import { useNuxtApp } from "#imports";
11
13
  const rootStore = useRootStore();
12
14
  const { $stores } = useNuxtApp();
13
15
  const props = defineProps(["type", "items", "name"]);
@@ -29,13 +29,15 @@
29
29
  </div>
30
30
  </template> -->
31
31
  </v-col>
32
- </template></v-row
33
- >
32
+ </template>
33
+ </v-row>
34
34
  </template>
35
35
 
36
36
  <script setup>
37
- import { useRootStore } from "../../../stores/root";
38
37
  import { useDisplay } from "vuetify";
38
+ import { resolveComponent } from "vue";
39
+ import { useRootStore } from "../../../stores/root";
40
+ import { useNuxtApp, useI18n } from "#imports";
39
41
  const { smAndDown } = useDisplay();
40
42
  const i18n = useI18n();
41
43
  const { locale, messages } = useI18n();
@@ -69,7 +71,7 @@ const computeVisibility = (filterItem) => {
69
71
  return (
70
72
  // if anything is set in the visibility key
71
73
  !$stores[props.type].filters[filterItem].visibility || $stores[props.type].filters[filterItem].visibility?.default || $stores[props.type].filters[filterItem].visibility?.switchIf.find(
72
- //for each of the rules set in the switchIf key
74
+ // for each of the rules set in the switchIf key
73
75
  (rule) => {
74
76
  return Object.keys(rule).find((value, index, obj) => {
75
77
  return $stores[props.type].filters[value].multiple ? $stores[props.type].filters[value]?.value && $stores[props.type].filters[value]?.value.includes(rule[value]) : $stores[props.type].filters[value]?.value === rule[value];
@@ -78,10 +78,9 @@
78
78
 
79
79
  <script setup>
80
80
  import { computed } from "vue";
81
- import { useRoute, useRouter } from "vue-router";
81
+ import { useRoute } from "vue-router";
82
82
  import { useRootStore } from "../../../stores/root";
83
83
  const route = useRoute();
84
- const router = useRouter();
85
84
  const rootStore = useRootStore();
86
85
  const props = defineProps({
87
86
  totalPages: {
@@ -189,7 +188,7 @@ watch(
189
188
  () => route.query.page,
190
189
  (newPage) => {
191
190
  if (newPage) {
192
- props.currentPage = parseInt(newPage, 10);
191
+ props.currentPage = Number.parseInt(newPage, 10);
193
192
  }
194
193
  },
195
194
  { immediate: true }
@@ -25,8 +25,10 @@
25
25
  </template>
26
26
 
27
27
  <script setup>
28
+ import { resolveComponent, computed } from "vue";
28
29
  import { useRootStore } from "../../../stores/root";
29
30
  import { capitalize } from "../../../composables/useUtils";
31
+ import { useNuxtApp, useI18n } from "#imports";
30
32
  const { $stores } = useNuxtApp();
31
33
  const { locale } = useI18n();
32
34
  const rootStore = useRootStore();
@@ -41,10 +41,12 @@
41
41
 
42
42
  <script setup>
43
43
  import { useDisplay } from "vuetify";
44
+ import { computed } from "vue";
44
45
  import {
45
46
  getDetailedFormatedDate,
46
47
  formatDateValue
47
48
  } from "../../../composables/useUtils";
49
+ import { useI18n } from "#imports";
48
50
  const { smAndDown, mdAndUp, name } = useDisplay();
49
51
  const { locale } = useI18n();
50
52
  const props = defineProps({
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <div>
3
- <!-- TODO
4
- - add skeleton UI
3
+ <!-- TODO
4
+ - add skeleton UI
5
5
  - test lazy-src
6
- - validate requested quality
7
- - Add conditional overlays slots (top left/right, bottom left/right/center for date, caption, copyright)-->
6
+ - validate requested quality
7
+ - Add conditional overlays slots (top left/right, bottom left/right/center for date, caption, copyright) -->
8
8
 
9
9
  <v-skeleton-loader v-if="loading" height="100%" type="image" />
10
10
 
@@ -50,6 +50,7 @@
50
50
  </template>
51
51
 
52
52
  <script setup>
53
+ import { computed } from "vue";
53
54
  const localePath = useLocalePath();
54
55
  const img = useImage();
55
56
  const computedSrc = computed(() => {
@@ -15,6 +15,7 @@
15
15
  </template>
16
16
 
17
17
  <script setup>
18
+ import { computed } from "vue";
18
19
  const props = defineProps({
19
20
  related: {
20
21
  type: Object,
@@ -25,9 +25,9 @@
25
25
  />
26
26
 
27
27
  <template v-else>
28
- <v-chip class="ma-2" style="background-color: white; color: black">{{
29
- $t(eventCategory)
30
- }}</v-chip>
28
+ <v-chip class="ma-2" style="background-color: white; color: black">
29
+ {{ $t(eventCategory) }}
30
+ </v-chip>
31
31
  <MiscMoleculesChipContainer :items="item.tags" size="small" />
32
32
  </template>
33
33
  </v-col>
@@ -36,7 +36,9 @@
36
36
 
37
37
  <script setup>
38
38
  import { useDisplay } from "vuetify";
39
+ import { computed } from "vue";
39
40
  import { useRootStore } from "../../stores/root";
41
+ import { useNuxtApp, useI18n, useLocalePath } from "#imports";
40
42
  const { $stores } = useNuxtApp();
41
43
  const { name } = useDisplay();
42
44
  const localePath = useLocalePath();
@@ -10,10 +10,10 @@
10
10
  link="news-slug"
11
11
  :slug="item._path && item._path.split('/').pop()"
12
12
  >
13
- <v-chip class="ma-2" style="background-color: white; color: black">{{
14
- $t(eventCategory)
15
- }}</v-chip></MiscAtomsImageContainer
16
- >
13
+ <v-chip class="ma-2" style="background-color: white; color: black">
14
+ {{ $t(eventCategory) }}
15
+ </v-chip>
16
+ </MiscAtomsImageContainer>
17
17
  </v-col>
18
18
  <v-col cols="12" md="8" lg="4" class="pl-md-6">
19
19
  <v-skeleton-loader
@@ -32,11 +32,11 @@
32
32
 
33
33
  <template v-else>
34
34
  <template v-if="smAndDown && item.category">
35
- <v-chip class="mb-4">{{
36
- $t("list.filters.news.category." + item.category)
37
- }}</v-chip>
38
- <br
39
- /></template>
35
+ <v-chip class="mb-4">
36
+ {{ $t("list.filters.news.category." + item.category) }}
37
+ </v-chip>
38
+ <br />
39
+ </template>
40
40
 
41
41
  <NuxtLink
42
42
  :to="
@@ -131,8 +131,10 @@
131
131
  </template>
132
132
 
133
133
  <script setup>
134
- import { useRootStore } from "../../stores/root";
135
134
  import { useDisplay } from "vuetify";
135
+ import { computed } from "vue";
136
+ import { useRootStore } from "../../stores/root";
137
+ import { useNuxtApp, useI18n } from "#imports";
136
138
  const { $stores } = useNuxtApp();
137
139
  const { locale } = useI18n();
138
140
  const localePath = useLocalePath();
@@ -10,9 +10,9 @@
10
10
  :type="['heading', 'heading'][['xs', 'sm'].indexOf(name || 'sm')]"
11
11
  />
12
12
  <template v-else>
13
- <v-chip v-if="item && item.category && item.name" class="mb-4">{{
14
- $t("list.filters.news.category." + item.category)
15
- }}</v-chip>
13
+ <v-chip v-if="item && item.category && item.name" class="mb-4">
14
+ {{ $t("list.filters.news.category." + item.category) }}
15
+ </v-chip>
16
16
  <br />
17
17
  {{ item.name }}
18
18
  </template>
@@ -47,9 +47,9 @@
47
47
  />
48
48
 
49
49
  <div v-else class="mx-4 mx-md-0 justify-md-end">
50
- <v-chip v-if="item && item.category && mdAndUp" class="mb-4">{{
51
- $t("list.filters.news.category." + item.category)
52
- }}</v-chip>
50
+ <v-chip v-if="item && item.category && mdAndUp" class="mb-4">
51
+ {{ $t("list.filters.news.category." + item.category) }}
52
+ </v-chip>
53
53
  <div
54
54
  v-if="item && item.name && mdAndUp"
55
55
  class="d-flex text-wrap text-h4 text-black"
@@ -161,6 +161,7 @@
161
161
 
162
162
  <script setup>
163
163
  import { useDisplay } from "vuetify";
164
+ import { useNuxtApp } from "#imports";
164
165
  const { $stores } = useNuxtApp();
165
166
  const { name, mdAndUp, smAndDown } = useDisplay();
166
167
  const props = defineProps({
@@ -22,6 +22,7 @@
22
22
 
23
23
  <script setup>
24
24
  import { useRootStore } from "../../stores/root";
25
+ import { useNuxtApp, useLocalePath } from "#imports";
25
26
  const { $stores } = useNuxtApp();
26
27
  const localePath = useLocalePath();
27
28
  const rootStore = useRootStore();
@@ -35,14 +35,15 @@
35
35
  tile
36
36
  variant="outlined"
37
37
  >
38
- {{ $t("list.filters.people.groups." + key) }}</v-chip
39
- ></template
40
- >
38
+ {{ $t("list.filters.people.groups." + key) }}
39
+ </v-chip>
40
+ </template>
41
41
  </div>
42
42
  </template>
43
43
 
44
44
  <script setup>
45
45
  import { useRootStore } from "../../stores/root";
46
+ import { useNuxtApp } from "#imports";
46
47
  const rootStore = useRootStore();
47
48
  const { $stores } = useNuxtApp();
48
49
  const props = defineProps({
@@ -66,6 +66,7 @@
66
66
 
67
67
  <script setup>
68
68
  import { useDisplay } from "vuetify";
69
+ import { computed } from "vue";
69
70
  const { name, mdAndUp } = useDisplay();
70
71
  const localePath = useLocalePath();
71
72
  const props = defineProps({
@@ -45,7 +45,7 @@
45
45
  class="my-8 text-h3 align-self-center text-wrap"
46
46
  >
47
47
  {{ item.firstname + " " + item.lastname
48
- }}<!-- TODO : call a composable to format people names (multiple, initials, capped & al. )-->
48
+ }}<!-- TODO : call a composable to format people names (multiple, initials, capped & al. ) -->
49
49
  </div>
50
50
  <!-- SOCIALS -->
51
51
  <div class="text-center">
@@ -151,6 +151,7 @@
151
151
 
152
152
  <script setup>
153
153
  import { useDisplay } from "vuetify";
154
+ import { useNuxtApp, useI18n } from "#imports";
154
155
  const { locale } = useI18n();
155
156
  const { $stores } = useNuxtApp();
156
157
  const { name, mdAndUp } = useDisplay();
@@ -114,6 +114,7 @@
114
114
 
115
115
  <script setup>
116
116
  import { useDisplay } from "vuetify";
117
+ import { useNuxtApp } from "#imports";
117
118
  const { $stores } = useNuxtApp();
118
119
  const { name } = useDisplay();
119
120
  const props = defineProps({
@@ -75,10 +75,11 @@
75
75
  ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].indexOf(name || 'md')
76
76
  ]
77
77
  "
78
- >{{ $t("visit-the-publications-website") }}</v-btn
79
78
  >
80
- ></template
81
- >
79
+ {{ $t("visit-the-publications-website") }}
80
+ </v-btn>
81
+ >
82
+ </template>
82
83
  </div>
83
84
  </v-col>
84
85
  <v-divider />
@@ -86,6 +87,7 @@
86
87
 
87
88
  <script setup>
88
89
  import { useDisplay } from "vuetify";
90
+ import { useNuxtApp, useI18n, useLocalePath, useRouter } from "#imports";
89
91
  const { name } = useDisplay();
90
92
  const { locale } = useI18n();
91
93
  const { $stores } = useNuxtApp();
@@ -115,6 +115,7 @@
115
115
 
116
116
  <script setup>
117
117
  import { useDisplay } from "vuetify";
118
+ import { useNuxtApp, useI18n } from "#imports";
118
119
  const { $stores } = useNuxtApp();
119
120
  const { name } = useDisplay();
120
121
  const { locale } = useI18n();
@@ -1,3 +1,4 @@
1
+ import { useNuxtApp } from "#imports";
1
2
  export const formatDate = (dateStr, locale) => {
2
3
  const date = new Date(dateStr);
3
4
  return date.toLocaleDateString(locale, {
@@ -1,5 +1,6 @@
1
1
  import { defineStore } from "pinia";
2
2
  import SEARCH from "../graphql/queries/list/search.gql";
3
+ import { useNuxtApp } from "#imports";
3
4
  export const useRootStore = defineStore("rootStore", {
4
5
  state: () => ({
5
6
  scrolled: import.meta.browser ? window.scrollY > 0 : false,
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.17",
4
+ "version": "1.0.19",
5
5
  "name": "@paris-ias/list",
6
6
  "repository": "IEA-Paris/list",
7
7
  "dependencies": {
@@ -1,143 +0,0 @@
1
- <template>
2
- <span> {{ displayedAmount }}</span>
3
- </template>
4
-
5
- <script setup>
6
- const props = defineProps({
7
- startAmount: {
8
- type: Number,
9
- default: 0
10
- },
11
- endAmount: {
12
- type: Number,
13
- default: 0,
14
- required: true
15
- },
16
- duration: {
17
- type: Number,
18
- default: 3,
19
- validator(duration) {
20
- return duration > 0;
21
- }
22
- },
23
- autoinit: {
24
- type: Boolean,
25
- default: true
26
- },
27
- prefix: {
28
- type: String,
29
- default: ""
30
- },
31
- suffix: {
32
- type: String,
33
- default: ""
34
- },
35
- separator: {
36
- type: String,
37
- default: ","
38
- },
39
- decimalSeparator: {
40
- type: String,
41
- default: "."
42
- },
43
- decimals: {
44
- type: Number,
45
- default: 0,
46
- validator(decimals) {
47
- return decimals >= 0;
48
- }
49
- }
50
- });
51
- const state = reactive({
52
- timestamp: 0,
53
- startTimestamp: null,
54
- currentAmount: props.startAmount,
55
- currentStartAmount: props.startAmount,
56
- currentDuration: props.duration * 1e3,
57
- paused: false,
58
- remaining: props.duration * 1e3,
59
- animationFrame: 0
60
- });
61
- const isCountingUp = computed(() => props.endAmount > props.startAmount);
62
- const formatedAmount = computed(() => {
63
- const regex = /(\d+)(\d{3})/;
64
- const numberString = state.currentAmount.toFixed(props.decimals);
65
- const numberArray = numberString.split(".");
66
- let numbers = numberArray[0];
67
- const decimals = numberArray.length > 1 ? props.decimalSeparator + numberArray[1] : "";
68
- const isNumber = !isNaN(parseFloat(props.separator));
69
- if (props.separator && !isNumber) {
70
- while (regex.test(numbers)) {
71
- numbers = numbers.replace(regex, "$1" + props.separator + "$2");
72
- }
73
- }
74
- return numbers + decimals;
75
- });
76
- const displayedAmount = computed(
77
- () => `${props.prefix}${formatedAmount.value}${props.suffix}`
78
- );
79
- const start = () => {
80
- cancelAnimation();
81
- state.currentStartAmount = props.startAmount;
82
- state.startTimestamp = null;
83
- state.currentDuration = props.duration * 1e3;
84
- state.paused = false;
85
- state.animationFrame = window.requestAnimationFrame(counting);
86
- };
87
- const pause = () => {
88
- if (state.paused) return;
89
- cancelAnimation();
90
- state.paused = true;
91
- };
92
- const resume = () => {
93
- if (!state.paused) return;
94
- state.startTimestamp = null;
95
- state.currentDuration = +state.remaining;
96
- state.currentStartAmount = +state.currentAmount;
97
- state.animationFrame = window.requestAnimationFrame(counting);
98
- state.paused = false;
99
- };
100
- const reset = () => {
101
- state.paused = false;
102
- state.startTimestamp = null;
103
- cancelAnimation();
104
- state.currentAmount = props.startAmount;
105
- if (props.autoinit) start();
106
- else state.paused = true;
107
- };
108
- const counting = (timestamp) => {
109
- state.timestamp = timestamp;
110
- if (!state.startTimestamp) state.startTimestamp = timestamp;
111
- const progress = timestamp - state.startTimestamp;
112
- state.remaining = state.currentDuration - progress;
113
- if (!isCountingUp.value) {
114
- state.currentAmount = state.currentStartAmount - (state.currentStartAmount - props.endAmount) * (progress / state.currentDuration);
115
- state.currentAmount = state.currentAmount < props.endAmount ? props.endAmount : state.currentAmount;
116
- } else {
117
- state.currentAmount = state.currentStartAmount + (props.endAmount - state.currentStartAmount) * (progress / state.currentDuration);
118
- state.currentAmount = state.currentAmount > props.endAmount ? props.endAmount : state.currentAmount;
119
- }
120
- if (progress < state.currentDuration) {
121
- state.animationFrame = window.requestAnimationFrame(counting);
122
- } else {
123
- console.log("finished");
124
- }
125
- };
126
- const cancelAnimation = () => {
127
- if (state.animationFrame) window.cancelAnimationFrame(state.animationFrame);
128
- };
129
- watch(() => props.startAmount, reset);
130
- watch(() => props.endAmount, reset);
131
- watch(() => props.duration, reset);
132
- onMounted(() => {
133
- state.currentAmount = props.startAmount;
134
- state.currentStartAmount = props.startAmount;
135
- state.currentDuration = props.duration * 1e3;
136
- state.remaining = props.duration * 1e3;
137
- if (props.autoinit) start();
138
- else state.paused = true;
139
- });
140
- onUnmounted(() => {
141
- cancelAnimation();
142
- });
143
- </script>