@explorer-1/vue 0.2.39 → 0.2.40
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/package.json +2 -2
- package/src/components/BaseCarousel/BaseCarousel.vue +152 -0
- package/src/components/BlockLinkCard/BlockLinkCard.vue +1 -0
- package/src/components/HeroListingIndex/HeroListingIndex.stories.js +92 -100
- package/src/components/HeroListingIndex/HeroListingIndex.vue +13 -15
- package/src/components/HeroMedium/HeroMedium.vue +1 -1
- package/src/components/MetadataEduResource/MetadataEduResource.vue +8 -2
- package/src/components/MetadataEvent/MetadataEvent.stories.js +1 -0
- package/src/components/MetadataEvent/MetadataEvent.vue +24 -8
- package/src/components/NavDesktop/NavDesktop.vue +6 -4
- package/src/components/NavDesktopEdu/NavDesktopEdu.vue +7 -3
- package/src/components/NavMobile/NavMobile.vue +5 -3
- package/src/components/NewsDetailMediaContact/NewsDetailMediaContact.vue +5 -3
- package/src/components/SearchFilterGroup/SearchFilterGroup.vue +26 -24
- package/src/components/SearchResultCard/SearchResultCard.vue +17 -1
- package/src/components/SearchResultGridItem/SearchResultGridItem.vue +17 -1
- package/src/components/SearchResultsList/SearchResultsList.vue +25 -1
- package/src/interfaces.ts +4 -0
- package/src/templates/www/PageTimeline/PageTimeline.vue +5 -1
- package/src/utils/mixins.ts +8 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explorer-1/vue",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.40",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"vue-bind-once": "^0.2.1",
|
|
31
31
|
"vue-observe-visibility": "^1.0.0",
|
|
32
32
|
"vue3-compare-image": "^1.2.5",
|
|
33
|
-
"@explorer-1/common": "1.1.
|
|
33
|
+
"@explorer-1/common": "1.1.11"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="BaseCarousel w-full overflow-hidden relative">
|
|
3
|
+
<div
|
|
4
|
+
ref="BaseCarousel"
|
|
5
|
+
class="swiper relative"
|
|
6
|
+
>
|
|
7
|
+
<div class="swiper-wrapper">
|
|
8
|
+
<slot />
|
|
9
|
+
</div>
|
|
10
|
+
<div class="swiper-nav lg:block absolute bottom-0 right-0 z-100">
|
|
11
|
+
<div class="relative z-10 flex">
|
|
12
|
+
<BaseButton
|
|
13
|
+
class="swiper-prev xl:text-xl border-collapse"
|
|
14
|
+
aria-label="Previous slide"
|
|
15
|
+
>
|
|
16
|
+
<template #icon>
|
|
17
|
+
<IconPrev />
|
|
18
|
+
</template>
|
|
19
|
+
</BaseButton>
|
|
20
|
+
<BaseButton
|
|
21
|
+
class="swiper-next xl:text-xl border-collapse"
|
|
22
|
+
aria-label="Next slide"
|
|
23
|
+
>
|
|
24
|
+
<template #icon>
|
|
25
|
+
<IconNext />
|
|
26
|
+
</template>
|
|
27
|
+
</BaseButton>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
<script lang="ts">
|
|
34
|
+
import { defineComponent } from 'vue'
|
|
35
|
+
import Swiper from 'swiper'
|
|
36
|
+
import { A11y, Navigation } from 'swiper/modules'
|
|
37
|
+
import type { SwiperOptions } from 'swiper/types'
|
|
38
|
+
import swiperOptions from '@explorer-1/common/src/js/_swiperOptions'
|
|
39
|
+
import IconPrev from './../Icons/IconPrev.vue'
|
|
40
|
+
import IconNext from './../Icons/IconNext.vue'
|
|
41
|
+
import BaseButton from './../BaseButton/BaseButton.vue'
|
|
42
|
+
const BaseCarouselOptions = swiperOptions.BlockImageCarousel
|
|
43
|
+
|
|
44
|
+
Swiper.use([Navigation, A11y])
|
|
45
|
+
|
|
46
|
+
export default defineComponent({
|
|
47
|
+
name: 'BaseCarousel',
|
|
48
|
+
components: {
|
|
49
|
+
BaseButton,
|
|
50
|
+
IconPrev,
|
|
51
|
+
IconNext
|
|
52
|
+
},
|
|
53
|
+
props: {
|
|
54
|
+
loop: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false
|
|
57
|
+
},
|
|
58
|
+
itemRole: {
|
|
59
|
+
type: String,
|
|
60
|
+
default: undefined
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
data(): {
|
|
64
|
+
currentIndex: number
|
|
65
|
+
slider: Swiper | null
|
|
66
|
+
currentCaption: string
|
|
67
|
+
sliderOptions: SwiperOptions
|
|
68
|
+
} {
|
|
69
|
+
return {
|
|
70
|
+
currentIndex: 0,
|
|
71
|
+
currentCaption: '',
|
|
72
|
+
slider: null,
|
|
73
|
+
sliderOptions: {
|
|
74
|
+
...BaseCarouselOptions,
|
|
75
|
+
loop: this.loop,
|
|
76
|
+
// this component has custom pagination
|
|
77
|
+
pagination: false,
|
|
78
|
+
a11y: {
|
|
79
|
+
slideRole: this.itemRole as string | undefined
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
computed: {},
|
|
85
|
+
watch: {
|
|
86
|
+
slide(value) {
|
|
87
|
+
this.slideTo(value)
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
mounted() {
|
|
91
|
+
this.init()
|
|
92
|
+
},
|
|
93
|
+
methods: {
|
|
94
|
+
init() {
|
|
95
|
+
this.slider = new Swiper(this.$refs.BaseCarousel as HTMLElement, this.sliderOptions)
|
|
96
|
+
this.currentIndex = this.slider.realIndex
|
|
97
|
+
},
|
|
98
|
+
updateIndex(val: number) {
|
|
99
|
+
this.currentIndex = val
|
|
100
|
+
},
|
|
101
|
+
slideTo(val: number) {
|
|
102
|
+
if (this.slider) {
|
|
103
|
+
this.slider.slideTo(val)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
</script>
|
|
109
|
+
<style lang="scss">
|
|
110
|
+
@import 'swiper/swiper-bundle.css';
|
|
111
|
+
.BaseCarousel {
|
|
112
|
+
.swiper {
|
|
113
|
+
.swiper-prev {
|
|
114
|
+
@apply mr-px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.swiper-prev,
|
|
118
|
+
.swiper-next {
|
|
119
|
+
&.swiper-button-disabled {
|
|
120
|
+
@apply opacity-75 cursor-default bg-none;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.swiper-nav {
|
|
126
|
+
padding-top: 56.25%;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// .swiper-dots {
|
|
130
|
+
// padding-top: 56.25%;
|
|
131
|
+
// @apply pointer-events-none;
|
|
132
|
+
|
|
133
|
+
// .swiper-dot {
|
|
134
|
+
// @apply inline-block px-1 py-3 cursor-pointer pointer-events-auto;
|
|
135
|
+
|
|
136
|
+
// &:focus {
|
|
137
|
+
// @apply outline-none ring-1;
|
|
138
|
+
// }
|
|
139
|
+
|
|
140
|
+
// > span {
|
|
141
|
+
// @apply inline-block w-3 h-3 rounded-full bg-gray-light-mid;
|
|
142
|
+
// }
|
|
143
|
+
|
|
144
|
+
// &.swiper-dot-active {
|
|
145
|
+
// > span {
|
|
146
|
+
// @apply bg-primary;
|
|
147
|
+
// }
|
|
148
|
+
// }
|
|
149
|
+
// }
|
|
150
|
+
// }
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
@@ -11,26 +11,24 @@ export default {
|
|
|
11
11
|
|
|
12
12
|
// data
|
|
13
13
|
export const HeroListingIndexData = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
url: 'https://picsum.photos/id/247/640/900'
|
|
33
|
-
}
|
|
14
|
+
featuredPage: {
|
|
15
|
+
__typename: 'EDUExplainerArticlePage',
|
|
16
|
+
topicLabel: 'Mars',
|
|
17
|
+
url: '/news/new-maps-open-roads-to-research/',
|
|
18
|
+
title: 'Creating Robots to go Where Humans Can’t',
|
|
19
|
+
image: {
|
|
20
|
+
src: {
|
|
21
|
+
url: 'https://picsum.photos/id/973/1800/1200',
|
|
22
|
+
width: 1800,
|
|
23
|
+
height: 1200
|
|
24
|
+
},
|
|
25
|
+
srcSet:
|
|
26
|
+
'https://picsum.photos/id/865/768/548 768w, https://picsum.photos/id/865/1024/684 1024w, https://picsum.photos/id/865/1440/770 1440w, https://picsum.photos/id/865/1800/963 1800w',
|
|
27
|
+
screenMd: {
|
|
28
|
+
url: 'https://picsum.photos/id/921/800/640'
|
|
29
|
+
},
|
|
30
|
+
screenSm: {
|
|
31
|
+
url: 'https://picsum.photos/id/247/640/900'
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
34
|
}
|
|
@@ -42,7 +40,7 @@ export const BaseStory = {
|
|
|
42
40
|
name: 'HeroListingIndex',
|
|
43
41
|
args: {
|
|
44
42
|
customLabel: 'Featured',
|
|
45
|
-
pageData: HeroListingIndexData.
|
|
43
|
+
pageData: HeroListingIndexData.featuredPage
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
46
|
|
|
@@ -50,31 +48,29 @@ export const NewsImageHero = {
|
|
|
50
48
|
args: {
|
|
51
49
|
customLabel: 'Featured',
|
|
52
50
|
pageData: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
url: 'https://picsum.photos/id/247/640/900'
|
|
73
|
-
}
|
|
51
|
+
topicLabel: 'Mars',
|
|
52
|
+
url: '/news/new-maps-open-roads-to-research/',
|
|
53
|
+
title: 'Creating Robots to go Where Humans Can’t',
|
|
54
|
+
heroBlocks: [
|
|
55
|
+
{
|
|
56
|
+
blockType: 'ImageChooserBlock',
|
|
57
|
+
listingPageHeroImage: {
|
|
58
|
+
src: {
|
|
59
|
+
url: 'https://picsum.photos/id/973/1800/1200',
|
|
60
|
+
width: 1800,
|
|
61
|
+
height: 1200
|
|
62
|
+
},
|
|
63
|
+
srcSet:
|
|
64
|
+
'https://picsum.photos/id/865/768/548 768w, https://picsum.photos/id/865/1024/684 1024w, https://picsum.photos/id/865/1440/770 1440w, https://picsum.photos/id/865/1800/963 1800w',
|
|
65
|
+
screenMd: {
|
|
66
|
+
url: 'https://picsum.photos/id/921/800/640'
|
|
67
|
+
},
|
|
68
|
+
screenSm: {
|
|
69
|
+
url: 'https://picsum.photos/id/247/640/900'
|
|
74
70
|
}
|
|
75
71
|
}
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
}
|
|
73
|
+
]
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
}
|
|
@@ -83,20 +79,18 @@ export const NewsVideoHero = {
|
|
|
83
79
|
args: {
|
|
84
80
|
customLabel: 'Featured',
|
|
85
81
|
pageData: {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
fileWebm: '/videos/NASA-Mars-Helicopter-IngenuityAnimations-7sec.webm'
|
|
96
|
-
}
|
|
82
|
+
topicLabel: 'Mars',
|
|
83
|
+
url: '/news/new-maps-open-roads-to-research/',
|
|
84
|
+
title: 'Creating Robots to go Where Humans Can’t',
|
|
85
|
+
heroBlocks: [
|
|
86
|
+
{
|
|
87
|
+
blockType: 'VideoBlock',
|
|
88
|
+
video: {
|
|
89
|
+
file: '/videos/NASA-Mars-Helicopter-IngenuityAnimations-7sec.mp4',
|
|
90
|
+
fileWebm: '/videos/NASA-Mars-Helicopter-IngenuityAnimations-7sec.webm'
|
|
97
91
|
}
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
}
|
|
93
|
+
]
|
|
100
94
|
}
|
|
101
95
|
}
|
|
102
96
|
}
|
|
@@ -105,52 +99,50 @@ export const NewsCarouselHero = {
|
|
|
105
99
|
args: {
|
|
106
100
|
customLabel: 'Featured',
|
|
107
101
|
pageData: {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
url: 'https://picsum.photos/id/247/640/900'
|
|
130
|
-
}
|
|
102
|
+
topicLabel: 'Mars',
|
|
103
|
+
url: '/news/new-maps-open-roads-to-research/',
|
|
104
|
+
title: 'Creating Robots to go Where Humans Can’t',
|
|
105
|
+
heroBlocks: [
|
|
106
|
+
{
|
|
107
|
+
blockType: 'CarouselBlock',
|
|
108
|
+
blocks: [
|
|
109
|
+
{
|
|
110
|
+
listingPageHeroImage: {
|
|
111
|
+
src: {
|
|
112
|
+
url: 'https://picsum.photos/id/973/1800/1200',
|
|
113
|
+
width: 1800,
|
|
114
|
+
height: 1200
|
|
115
|
+
},
|
|
116
|
+
srcSet:
|
|
117
|
+
'https://picsum.photos/id/865/768/548 768w, https://picsum.photos/id/865/1024/684 1024w, https://picsum.photos/id/865/1440/770 1440w, https://picsum.photos/id/865/1800/963 1800w',
|
|
118
|
+
screenMd: {
|
|
119
|
+
url: 'https://picsum.photos/id/921/800/640'
|
|
120
|
+
},
|
|
121
|
+
screenSm: {
|
|
122
|
+
url: 'https://picsum.photos/id/247/640/900'
|
|
131
123
|
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
listingPageHeroImage: {
|
|
128
|
+
src: {
|
|
129
|
+
url: 'https://picsum.photos/id/973/1800/1200',
|
|
130
|
+
width: 1800,
|
|
131
|
+
height: 1200
|
|
132
|
+
},
|
|
133
|
+
srcSet:
|
|
134
|
+
'https://picsum.photos/id/865/768/548 768w, https://picsum.photos/id/865/1024/684 1024w, https://picsum.photos/id/865/1440/770 1440w, https://picsum.photos/id/865/1800/963 1800w',
|
|
135
|
+
screenMd: {
|
|
136
|
+
url: 'https://picsum.photos/id/921/800/640'
|
|
137
|
+
},
|
|
138
|
+
screenSm: {
|
|
139
|
+
url: 'https://picsum.photos/id/247/640/900'
|
|
148
140
|
}
|
|
149
141
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
]
|
|
154
146
|
}
|
|
155
147
|
}
|
|
156
148
|
}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
v-if="pageData"
|
|
4
|
-
class="max-w-screen-3xl mx-auto"
|
|
5
|
-
:class="{ '-nav-offset': pageData
|
|
4
|
+
class="HeroListingIndex max-w-screen-3xl mx-auto"
|
|
5
|
+
:class="{ '-nav-offset': pageData }"
|
|
6
6
|
>
|
|
7
7
|
<HeroMedium
|
|
8
|
-
v-if="pageData
|
|
8
|
+
v-if="pageData"
|
|
9
9
|
class="md:mb-12 lg:mb-18 mb-10"
|
|
10
10
|
:custom-pill="themeStore.theme === 'ThemeEdu' && customLabel ? customLabel : undefined"
|
|
11
11
|
:custom-pill-type="
|
|
12
|
-
themeStore.theme === 'ThemeEdu' && pageData.
|
|
13
|
-
? pageData.featured.__typename
|
|
14
|
-
: undefined
|
|
12
|
+
themeStore.theme === 'ThemeEdu' && pageData.__typename ? pageData.__typename : undefined
|
|
15
13
|
"
|
|
16
|
-
:custom-label="themeStore.theme === 'ThemeEdu' ? pageData.
|
|
17
|
-
:feature="pageData
|
|
14
|
+
:custom-label="themeStore.theme === 'ThemeEdu' ? pageData.topicLabel : customLabel"
|
|
15
|
+
:feature="pageData"
|
|
18
16
|
:custom-video="customVideo"
|
|
19
17
|
:custom-image="customImage"
|
|
20
18
|
:cta="cta"
|
|
@@ -54,17 +52,17 @@ export default defineComponent({
|
|
|
54
52
|
...mapStores(useThemeStore),
|
|
55
53
|
// parses a hero streamfield block for a video (newsDetailPage model)
|
|
56
54
|
customVideo(): object | undefined {
|
|
57
|
-
if (this.pageData && this.pageData
|
|
58
|
-
if (this.pageData.
|
|
59
|
-
return this.pageData.
|
|
55
|
+
if (this.pageData && this.pageData?.heroBlocks?.length > 0) {
|
|
56
|
+
if (this.pageData.heroBlocks[0].blockType === 'VideoBlock') {
|
|
57
|
+
return this.pageData.heroBlocks[0].video
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
return undefined
|
|
63
61
|
},
|
|
64
62
|
customImage(): object | undefined {
|
|
65
63
|
// parse hero streamfield block for the first usable image (newsDetailPage model)
|
|
66
|
-
if (this.pageData
|
|
67
|
-
const block = this.pageData
|
|
64
|
+
if (this.pageData?.heroBlocks?.length > 0) {
|
|
65
|
+
const block = this.pageData?.heroBlocks[0]
|
|
68
66
|
if (block.blockType === 'ImageChooserBlock' || block.blockType === 'HeroImageBlock') {
|
|
69
67
|
return block.listingPageHeroImage
|
|
70
68
|
} else if (block.blockType === 'CarouselBlock') {
|
|
@@ -75,8 +73,8 @@ export default defineComponent({
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
// else use heroImage
|
|
78
|
-
else if (this.pageData?.
|
|
79
|
-
return this.pageData.
|
|
76
|
+
else if (this.pageData?.listingPageHeroImage) {
|
|
77
|
+
return this.pageData.listingPageHeroImage
|
|
80
78
|
}
|
|
81
79
|
return undefined
|
|
82
80
|
}
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
<p class="text-h3 font-semibold mb-0">
|
|
75
75
|
<span class="mr-2">{{ feature.title }}</span>
|
|
76
76
|
<span
|
|
77
|
-
class="text-
|
|
77
|
+
class="text-action-light lg:hidden can-hover:group-hover:ml-2 ml-0 text-4xl transition-all duration-200 ease-in"
|
|
78
78
|
>
|
|
79
79
|
<IconArrow class="inline" />
|
|
80
80
|
</span>
|
|
@@ -11,12 +11,14 @@ interface MetadataEduResourceProps {
|
|
|
11
11
|
resource: EduResourceCardObject
|
|
12
12
|
compact?: boolean
|
|
13
13
|
variant?: string
|
|
14
|
+
showTime: boolean
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
// define props
|
|
17
18
|
const props = withDefaults(defineProps<MetadataEduResourceProps>(), {
|
|
18
19
|
resource: undefined,
|
|
19
20
|
compact: false,
|
|
21
|
+
showTime: false,
|
|
20
22
|
variant: 'primary'
|
|
21
23
|
})
|
|
22
24
|
|
|
@@ -30,7 +32,11 @@ const audience = computed(() => {
|
|
|
30
32
|
return rangeifyGrades(props.resource?.gradeLevels)
|
|
31
33
|
})
|
|
32
34
|
const time = computed(() => {
|
|
33
|
-
|
|
35
|
+
let time = props.resource?.time?.time
|
|
36
|
+
if (time && props.compact) {
|
|
37
|
+
time = time.replace('Under ', '<')
|
|
38
|
+
}
|
|
39
|
+
return time
|
|
34
40
|
})
|
|
35
41
|
</script>
|
|
36
42
|
<template>
|
|
@@ -61,7 +67,7 @@ const time = computed(() => {
|
|
|
61
67
|
<span>{{ audience }}</span>
|
|
62
68
|
</div>
|
|
63
69
|
<div
|
|
64
|
-
v-if="time &&
|
|
70
|
+
v-if="time && showTime"
|
|
65
71
|
class="MetadataEduResourceItem"
|
|
66
72
|
>
|
|
67
73
|
<IconTime
|
|
@@ -52,8 +52,24 @@ const displayTime = computed((): string => {
|
|
|
52
52
|
}
|
|
53
53
|
return ''
|
|
54
54
|
})
|
|
55
|
-
const
|
|
56
|
-
|
|
55
|
+
const location = computed(() => {
|
|
56
|
+
if (props.event?.location) {
|
|
57
|
+
return props.event?.location
|
|
58
|
+
} else if (props.compact) {
|
|
59
|
+
let text = 'Hybrid'
|
|
60
|
+
let virtual = props.event.isVirtualEvent
|
|
61
|
+
let inPerson = props.event.isInPersonEvent
|
|
62
|
+
if (props.event?.isVirtualEvent && props) {
|
|
63
|
+
if (virtual && !inPerson) {
|
|
64
|
+
text = 'Online'
|
|
65
|
+
} else if (!virtual && inPerson) {
|
|
66
|
+
text = 'In-person'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return text
|
|
70
|
+
} else {
|
|
71
|
+
return props.event?.locationName
|
|
72
|
+
}
|
|
57
73
|
})
|
|
58
74
|
</script>
|
|
59
75
|
<template>
|
|
@@ -96,7 +112,7 @@ const locationName = computed(() => {
|
|
|
96
112
|
/>
|
|
97
113
|
<meta
|
|
98
114
|
itemprop="name"
|
|
99
|
-
:content="
|
|
115
|
+
:content="location"
|
|
100
116
|
/>
|
|
101
117
|
<IconLocation class="MetadataEventIcon text-[1.1em]" />
|
|
102
118
|
<BaseLink
|
|
@@ -105,18 +121,18 @@ const locationName = computed(() => {
|
|
|
105
121
|
:href="props.event.locationLink"
|
|
106
122
|
external-target-blank
|
|
107
123
|
>
|
|
108
|
-
{{
|
|
124
|
+
{{ location }}
|
|
109
125
|
</BaseLink>
|
|
110
126
|
</div>
|
|
111
127
|
<!-- Normal location -->
|
|
112
128
|
<div
|
|
113
|
-
v-else-if="
|
|
129
|
+
v-else-if="location"
|
|
114
130
|
class="MetadataEventItem"
|
|
115
131
|
>
|
|
116
132
|
<meta
|
|
117
133
|
v-if="!props.compact"
|
|
118
134
|
itemprop="location"
|
|
119
|
-
:content="
|
|
135
|
+
:content="location"
|
|
120
136
|
/>
|
|
121
137
|
<IconLocation class="MetadataEventIcon text-[1.2em]" />
|
|
122
138
|
<BaseLink
|
|
@@ -126,9 +142,9 @@ const locationName = computed(() => {
|
|
|
126
142
|
:href="props.event.locationLink"
|
|
127
143
|
external-target-blank
|
|
128
144
|
>
|
|
129
|
-
{{
|
|
145
|
+
{{ location }}
|
|
130
146
|
</BaseLink>
|
|
131
|
-
<span v-else>{{
|
|
147
|
+
<span v-else>{{ location }}</span>
|
|
132
148
|
</div>
|
|
133
149
|
</template>
|
|
134
150
|
</div>
|
|
@@ -250,9 +250,9 @@ export default defineComponent({
|
|
|
250
250
|
// key into the breadcrumbs for each section
|
|
251
251
|
const sectionLinks = this.breadcrumb.menu_links[urlKey]
|
|
252
252
|
// check if any of the paths contained in the array are active
|
|
253
|
-
const isActive = sectionLinks
|
|
254
|
-
mixinIsActivePath(link.path)
|
|
255
|
-
|
|
253
|
+
const isActive = sectionLinks?.length
|
|
254
|
+
? sectionLinks.some((link: BreadcrumbPathObject) => mixinIsActivePath(link.path))
|
|
255
|
+
: undefined
|
|
256
256
|
if (isActive) {
|
|
257
257
|
mixinUpdateGlobalChildren(sectionLinks)
|
|
258
258
|
}
|
|
@@ -265,7 +265,9 @@ export default defineComponent({
|
|
|
265
265
|
// get the more menu array
|
|
266
266
|
const arr = this.breadcrumb.more
|
|
267
267
|
// check if array contains current path
|
|
268
|
-
const isActive = arr
|
|
268
|
+
const isActive = arr?.length
|
|
269
|
+
? arr.some((el: BreadcrumbPathObject) => mixinIsActivePath(el.path))
|
|
270
|
+
: undefined
|
|
269
271
|
if (isActive) {
|
|
270
272
|
// clear the secondary nav store when visiting a breadcrumb page
|
|
271
273
|
// ensures blank secondary nav unless explicitly set via content page "Promote" settings
|
|
@@ -254,7 +254,9 @@ export default defineComponent({
|
|
|
254
254
|
// key into the breadcrumbs for each section
|
|
255
255
|
const objArray = this.breadcrumb.menu_links[urlKey]
|
|
256
256
|
// check if any of the paths contained in the array are active
|
|
257
|
-
const isActive = objArray
|
|
257
|
+
const isActive = objArray?.length
|
|
258
|
+
? objArray.some((el: BreadcrumbPathObject) => mixinIsActivePath(el.path))
|
|
259
|
+
: undefined
|
|
258
260
|
if (isActive) {
|
|
259
261
|
mixinUpdateGlobalChildren(this.breadcrumb.menu_links[urlKey])
|
|
260
262
|
}
|
|
@@ -267,7 +269,9 @@ export default defineComponent({
|
|
|
267
269
|
// get the more menu array
|
|
268
270
|
const arr = this.breadcrumb.more
|
|
269
271
|
// check if array contains current path
|
|
270
|
-
const isActive = arr
|
|
272
|
+
const isActive = arr?.length
|
|
273
|
+
? arr.some((el: BreadcrumbPathObject) => mixinIsActivePath(el.path))
|
|
274
|
+
: undefined
|
|
271
275
|
if (isActive) {
|
|
272
276
|
// clear the secondary nav store when visiting a breadcrumb page
|
|
273
277
|
// ensures blank secondary nav unless explicitly set via content page "Promote" settings
|
|
@@ -300,7 +304,7 @@ export default defineComponent({
|
|
|
300
304
|
</script>
|
|
301
305
|
<style lang="scss">
|
|
302
306
|
.NavDesktopEdu {
|
|
303
|
-
@apply border-
|
|
307
|
+
@apply border-none;
|
|
304
308
|
|
|
305
309
|
> .header-bg {
|
|
306
310
|
@apply bg-gradient-to-r from-black to-primary bg-transparent to-90%;
|
|
@@ -280,9 +280,11 @@ export default defineComponent({
|
|
|
280
280
|
// key into the breadcrumbs for each section
|
|
281
281
|
const objArray = this.breadcrumb.menu_links[urlKey]
|
|
282
282
|
// check if any of the paths contained in the array are active
|
|
283
|
-
return objArray
|
|
284
|
-
|
|
285
|
-
|
|
283
|
+
return objArray?.length
|
|
284
|
+
? objArray.some((el: BreadcrumbPathObject) => {
|
|
285
|
+
return mixinIsActivePath(el.path)
|
|
286
|
+
})
|
|
287
|
+
: undefined
|
|
286
288
|
}
|
|
287
289
|
return false
|
|
288
290
|
}
|
|
@@ -42,9 +42,11 @@ export default defineComponent({
|
|
|
42
42
|
},
|
|
43
43
|
computed: {
|
|
44
44
|
hasContent() {
|
|
45
|
-
return this.contacts
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
return this.contacts?.length
|
|
46
|
+
? this.contacts.some(
|
|
47
|
+
(c) => c.contact.name || c.contact.address || c.contact.phone || c.contact.email
|
|
48
|
+
)
|
|
49
|
+
: undefined
|
|
48
50
|
}
|
|
49
51
|
},
|
|
50
52
|
methods: {
|
|
@@ -13,32 +13,34 @@
|
|
|
13
13
|
<legend class="md:mb-3 text-body-md mb-2 font-bold leading-normal tracking-wide">
|
|
14
14
|
{{ groupTitle }}
|
|
15
15
|
</legend>
|
|
16
|
-
<div
|
|
17
|
-
v-for="(bucket, index) in buckets"
|
|
18
|
-
:key="bucket.key"
|
|
19
|
-
ref="buckets"
|
|
20
|
-
class="form-group form-check"
|
|
21
|
-
>
|
|
22
|
-
<!-- correct for zero based index -->
|
|
16
|
+
<div class="buckets">
|
|
23
17
|
<div
|
|
24
|
-
v-
|
|
25
|
-
|
|
18
|
+
v-for="(bucket, index) in buckets"
|
|
19
|
+
:key="bucket.key"
|
|
20
|
+
ref="buckets"
|
|
21
|
+
class="form-group form-check"
|
|
26
22
|
>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
v-
|
|
30
|
-
|
|
31
|
-
:value="bucket.key_as_string ? bucket.key_as_string : bucket.key"
|
|
32
|
-
class="text-primary focus:ring-2 focus:ring-primary flex-shrink-0 w-5 h-5 mt-px mr-1 align-middle border rounded-none"
|
|
33
|
-
/>
|
|
34
|
-
<!-- 'key_as_string' exists for dates to have a human readable version -->
|
|
35
|
-
<label
|
|
36
|
-
:for="bucket.key_as_string ? generateId(bucket.key_as_string) : generateId(bucket.key)"
|
|
37
|
-
class="form-check-label pl-2 tracking-normal align-middle"
|
|
23
|
+
<!-- correct for zero based index -->
|
|
24
|
+
<div
|
|
25
|
+
v-if="!truncateFilters || index <= checkbox.checkboxLimit - 1"
|
|
26
|
+
class="flex my-2"
|
|
38
27
|
>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
28
|
+
<input
|
|
29
|
+
:id="bucket.key_as_string ? generateId(bucket.key_as_string) : generateId(bucket.key)"
|
|
30
|
+
v-model="filterByHandler"
|
|
31
|
+
type="checkbox"
|
|
32
|
+
:value="bucket.key_as_string ? bucket.key_as_string : bucket.key"
|
|
33
|
+
class="text-primary focus:ring-2 focus:ring-primary flex-shrink-0 w-5 h-5 mt-px mr-1 align-middle border rounded-none"
|
|
34
|
+
/>
|
|
35
|
+
<!-- 'key_as_string' exists for dates to have a human readable version -->
|
|
36
|
+
<label
|
|
37
|
+
:for="bucket.key_as_string ? generateId(bucket.key_as_string) : generateId(bucket.key)"
|
|
38
|
+
class="form-check-label pl-2 tracking-normal align-middle"
|
|
39
|
+
>
|
|
40
|
+
{{ prettyFilterNames(bucket.key_as_string ? bucket.key_as_string : bucket.key) }}
|
|
41
|
+
<span class="text-gray-mid-dark"> ({{ bucket.doc_count.toLocaleString() }}) </span>
|
|
42
|
+
</label>
|
|
43
|
+
</div>
|
|
42
44
|
</div>
|
|
43
45
|
</div>
|
|
44
46
|
<!--
|
|
@@ -49,7 +51,7 @@
|
|
|
49
51
|
|
|
50
52
|
<div v-show="truncateFilters && bucketsLength > checkbox.initialLimit">
|
|
51
53
|
<button
|
|
52
|
-
class="can-hover:hover:underline text-
|
|
54
|
+
class="can-hover:hover:underline text-action mt-2"
|
|
53
55
|
:aria-expanded="!checkbox.showMore ? 'true' : 'false'"
|
|
54
56
|
aria-haspopup="true"
|
|
55
57
|
:aria-controls="`filterGroup_${groupKey}`"
|
|
@@ -21,7 +21,10 @@
|
|
|
21
21
|
customDate,
|
|
22
22
|
location,
|
|
23
23
|
eventType,
|
|
24
|
-
ongoing
|
|
24
|
+
ongoing,
|
|
25
|
+
primarySubject,
|
|
26
|
+
gradeLevels,
|
|
27
|
+
time
|
|
25
28
|
}
|
|
26
29
|
}"
|
|
27
30
|
show-calendar-chip
|
|
@@ -211,6 +214,7 @@
|
|
|
211
214
|
import type { PropType } from 'vue'
|
|
212
215
|
import { defineComponent } from 'vue'
|
|
213
216
|
import { mapStores } from 'pinia'
|
|
217
|
+
import type { PrimarySubjectObject, GradeLevelsObject, EduResourcesTime } from './../../interfaces'
|
|
214
218
|
import { useThemeStore } from '../../store/theme'
|
|
215
219
|
import PodcastEpisodeCard from './../PodcastEpisodeCard/PodcastEpisodeCard.vue'
|
|
216
220
|
import BaseLink from './../BaseLink/BaseLink.vue'
|
|
@@ -338,6 +342,18 @@ export default defineComponent({
|
|
|
338
342
|
ongoing: {
|
|
339
343
|
type: Boolean,
|
|
340
344
|
default: false
|
|
345
|
+
},
|
|
346
|
+
primarySubject: {
|
|
347
|
+
type: Object as PropType<PrimarySubjectObject>,
|
|
348
|
+
default: undefined
|
|
349
|
+
},
|
|
350
|
+
gradeLevels: {
|
|
351
|
+
type: Array as PropType<GradeLevelsObject[]>,
|
|
352
|
+
default: undefined
|
|
353
|
+
},
|
|
354
|
+
time: {
|
|
355
|
+
type: Object as PropType<EduResourcesTime>,
|
|
356
|
+
default: undefined
|
|
341
357
|
}
|
|
342
358
|
},
|
|
343
359
|
computed: {
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
customDate,
|
|
19
19
|
location,
|
|
20
20
|
eventType,
|
|
21
|
-
ongoing
|
|
21
|
+
ongoing,
|
|
22
|
+
primarySubject,
|
|
23
|
+
gradeLevels,
|
|
24
|
+
time
|
|
22
25
|
}
|
|
23
26
|
}"
|
|
24
27
|
:heading-level="headingLevel"
|
|
@@ -94,6 +97,7 @@
|
|
|
94
97
|
import type { PropType } from 'vue'
|
|
95
98
|
import { defineComponent } from 'vue'
|
|
96
99
|
import { mapStores } from 'pinia'
|
|
100
|
+
import type { PrimarySubjectObject, GradeLevelsObject, EduResourcesTime } from './../../interfaces'
|
|
97
101
|
import { useThemeStore } from '../../store/theme'
|
|
98
102
|
import BaseLink from './../BaseLink/BaseLink.vue'
|
|
99
103
|
import BaseImage from './../BaseImage/BaseImage.vue'
|
|
@@ -181,6 +185,18 @@ export default defineComponent({
|
|
|
181
185
|
pageContentType: {
|
|
182
186
|
type: String,
|
|
183
187
|
required: false
|
|
188
|
+
},
|
|
189
|
+
primarySubject: {
|
|
190
|
+
type: Object as PropType<PrimarySubjectObject>,
|
|
191
|
+
default: undefined
|
|
192
|
+
},
|
|
193
|
+
gradeLevels: {
|
|
194
|
+
type: Array as PropType<GradeLevelsObject[]>,
|
|
195
|
+
default: undefined
|
|
196
|
+
},
|
|
197
|
+
time: {
|
|
198
|
+
type: Object as PropType<EduResourcesTime>,
|
|
199
|
+
default: undefined
|
|
184
200
|
}
|
|
185
201
|
},
|
|
186
202
|
computed: {
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
:event-type="page.eventType"
|
|
32
32
|
:ongoing="page.ongoing"
|
|
33
33
|
:location="page.location"
|
|
34
|
+
:primary-subject="page.primarySubject as unknown as PrimarySubjectObject"
|
|
35
|
+
:grade-levels="page.gradeLevels as unknown as GradeLevelsObject[]"
|
|
36
|
+
:time="page.time as unknown as EduResourcesTime"
|
|
34
37
|
:title="page.title"
|
|
35
38
|
:summary="page.summary"
|
|
36
39
|
:featured="featureFirstResult ? index === 0 && currentPage === 1 : false"
|
|
@@ -53,6 +56,9 @@
|
|
|
53
56
|
:event-type="page.eventType"
|
|
54
57
|
:ongoing="page.ongoing"
|
|
55
58
|
:location="page.location"
|
|
59
|
+
:primary-subject="page.primarySubject as unknown as PrimarySubjectObject"
|
|
60
|
+
:grade-levels="page.gradeLevels as unknown as GradeLevelsObject[]"
|
|
61
|
+
:time="page.time as unknown as EduResourcesTime"
|
|
56
62
|
:title="page.title"
|
|
57
63
|
heading-level="h2"
|
|
58
64
|
/>
|
|
@@ -64,7 +70,7 @@
|
|
|
64
70
|
<script lang="ts">
|
|
65
71
|
import { defineComponent } from 'vue'
|
|
66
72
|
import type { ElasticSearchPage } from '../../interfaces'
|
|
67
|
-
|
|
73
|
+
import type { PrimarySubjectObject, GradeLevelsObject, EduResourcesTime } from './../../interfaces'
|
|
68
74
|
// @ts-ignore
|
|
69
75
|
import dayjs from 'dayjs'
|
|
70
76
|
import SearchResultCard from './../SearchResultCard/SearchResultCard.vue'
|
|
@@ -131,6 +137,9 @@ export default defineComponent({
|
|
|
131
137
|
// date field is different for mission and event detail pages
|
|
132
138
|
let date
|
|
133
139
|
let location
|
|
140
|
+
let primarySubject
|
|
141
|
+
let gradeLevels
|
|
142
|
+
let time
|
|
134
143
|
let topic =
|
|
135
144
|
handle === 'missions_mission'
|
|
136
145
|
? page._source[handle + '__status_filter']
|
|
@@ -152,6 +161,17 @@ export default defineComponent({
|
|
|
152
161
|
} else if (handle === 'profiles_profilepage') {
|
|
153
162
|
topic = page._source[handle + '__go_site_name']
|
|
154
163
|
date = null
|
|
164
|
+
} else if (handle.startsWith('edu_resources')) {
|
|
165
|
+
date = null
|
|
166
|
+
primarySubject = page._source[handle + '__primary_subject'] as PrimarySubjectObject
|
|
167
|
+
if (page._source[handle + '__grade_levels']) {
|
|
168
|
+
gradeLevels = [] as GradeLevelsObject[]
|
|
169
|
+
// @ts-expect-error
|
|
170
|
+
page._source[handle + '__grade_levels'].forEach((level) => {
|
|
171
|
+
gradeLevels.push({ gradeLevel: level.grade_level })
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
time = { time: page._source.activity_time_label_filter } as EduResourcesTime
|
|
155
175
|
} else {
|
|
156
176
|
date =
|
|
157
177
|
typeof page._source.publication_date_filter !== 'undefined'
|
|
@@ -196,6 +216,10 @@ export default defineComponent({
|
|
|
196
216
|
handle === 'edu_events_edueventpage'
|
|
197
217
|
? page._source.edu_events_edueventpage__ongoing
|
|
198
218
|
: undefined
|
|
219
|
+
// edu resources
|
|
220
|
+
page.gradeLevels = gradeLevels
|
|
221
|
+
page.time = time
|
|
222
|
+
page.primarySubject = primarySubject
|
|
199
223
|
// properties that are different for profiles page
|
|
200
224
|
page.summary =
|
|
201
225
|
handle === 'profiles_profilepage'
|
package/src/interfaces.ts
CHANGED
|
@@ -92,6 +92,9 @@ export interface ElasticSearchPage {
|
|
|
92
92
|
summary?: string
|
|
93
93
|
eventType?: string
|
|
94
94
|
ongoing?: boolean
|
|
95
|
+
primarySubject?: string
|
|
96
|
+
gradeLevels: string
|
|
97
|
+
time: string
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
export interface FormOption {
|
|
@@ -129,6 +132,7 @@ export interface EventCardObject extends Card {
|
|
|
129
132
|
eventType?: string
|
|
130
133
|
ongoing?: boolean
|
|
131
134
|
isVirtualEvent?: boolean
|
|
135
|
+
isInPersonEvent?: boolean
|
|
132
136
|
locationName?: string
|
|
133
137
|
location?: string
|
|
134
138
|
locationLink?: string
|
|
@@ -209,7 +209,11 @@ export default defineComponent({
|
|
|
209
209
|
},
|
|
210
210
|
created() {
|
|
211
211
|
const sortByParam = this.$route?.query.sortBy
|
|
212
|
-
if (
|
|
212
|
+
if (
|
|
213
|
+
sortByParam &&
|
|
214
|
+
sortByOptions &&
|
|
215
|
+
sortByOptions.some((option) => option.value === sortByParam)
|
|
216
|
+
) {
|
|
213
217
|
this.sortBy = sortByParam as SortBy
|
|
214
218
|
}
|
|
215
219
|
|
package/src/utils/mixins.ts
CHANGED
|
@@ -194,12 +194,14 @@ export const mixinIsActivePath = (itemPath: string): Boolean => {
|
|
|
194
194
|
*/
|
|
195
195
|
export const mixinGetSrcSet = (srcSetObject: Partial<ImageObject>): string => {
|
|
196
196
|
let srcSet = ''
|
|
197
|
-
const valid = Object.keys(srcSetObject)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
const valid = Object.keys(srcSetObject)?.length
|
|
198
|
+
? Object.keys(srcSetObject).some(function (key) {
|
|
199
|
+
if (key.startsWith('screen')) {
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
return false
|
|
203
|
+
})
|
|
204
|
+
: false
|
|
203
205
|
if (valid) {
|
|
204
206
|
const srcSetArray: string[] = []
|
|
205
207
|
for (const [key, value] of Object.entries(srcSetObject)) {
|