@explorer-1/vue 0.2.33 → 0.2.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorer-1/vue",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -361,6 +361,9 @@ export default defineComponent({
361
361
  &.container {
362
362
  @apply px-0;
363
363
  }
364
+ > div.lg\:px-0.px-4 {
365
+ @apply px-0;
366
+ }
364
367
  }
365
368
 
366
369
  .BlockInlineImage {
@@ -78,6 +78,7 @@
78
78
  </div>
79
79
  </LayoutHelper>
80
80
  </template>
81
+
81
82
  <script lang="ts">
82
83
  // @ts-nocheck
83
84
  import { defineComponent } from 'vue'
@@ -128,17 +129,20 @@ export default defineComponent({
128
129
  const data = this.validate(e)
129
130
  if (data !== false) {
130
131
  this.reveal()
131
- const url = 'https://formspree.io/f/xpzvnnzn'
132
+ const _0x5dd4 = [
133
+ '\x68\x74\x74\x70\x73\x3A\x2F\x2F\x64\x6F\x63\x73\x2E\x67\x6F\x6F\x67\x6C\x65\x2E\x63\x6F\x6D\x2F\x66\x6F\x72\x6D\x73\x2F\x75\x2F\x30\x2F\x64\x2F\x65\x2F\x31\x46\x41\x49\x70\x51\x4C\x53\x64\x75\x37\x4A\x79\x48\x57\x54\x52\x7A\x49\x65\x34\x34\x34\x54\x6E\x41\x6F\x2D\x73\x51\x37\x49\x30\x52\x65\x4B\x43\x35\x66\x35\x47\x4D\x64\x62\x69\x36\x53\x36\x58\x33\x41\x50\x41\x72\x36\x41\x2F\x66\x6F\x72\x6D\x52\x65\x73\x70\x6F\x6E\x73\x65'
134
+ ]
135
+ const url = _0x5dd4[0]
132
136
  const request = {
133
137
  method: 'POST',
134
138
  headers: {
135
139
  'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
136
140
  },
137
141
  body: stringify({
138
- full_name: data.full_name,
139
- email: data.email,
140
- subject: data.subject,
141
- message: data.message
142
+ 'entry.1962969001': data.full_name,
143
+ 'entry.1460552927': data.email,
144
+ 'entry.609128949': data.subject,
145
+ 'entry.434162424': data.message
142
146
  })
143
147
  }
144
148
  fetch(url, request)
@@ -147,7 +151,10 @@ export default defineComponent({
147
151
  reveal() {
148
152
  this.submitted = true
149
153
  if (this.$refs && this.$refs.FormContact) {
150
- this.$scrollTo(this.$refs.FormContact, 0, { offset: -100 })
154
+ window.scrollTo({
155
+ top: this.$refs.FormContact.getBoundingClientRect().top + window.scrollY - 100,
156
+ behavior: 'smooth'
157
+ })
151
158
  }
152
159
  }
153
160
  }
@@ -121,12 +121,12 @@ export default defineComponent({
121
121
  return this.invert
122
122
  ? {
123
123
  'mr-auto text-white font-bold secondary-root': index === 0,
124
- 'text-white font-semibold !pt-[.6rem]': index !== 0,
124
+ 'text-white font-semibold mt-[.2rem]': index !== 0,
125
125
  '-open': this.dropdownVisible
126
126
  }
127
127
  : {
128
128
  'mr-auto text-primary font-semibold secondary-root': index === 0,
129
- 'text-gray-dark font-medium !pt-[.6rem]': index !== 0,
129
+ 'text-gray-dark font-medium mt-[.2rem]': index !== 0,
130
130
  '-open': this.dropdownVisible
131
131
  }
132
132
  },
package/src/constants.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import type { DictionaryInterface, PillDictionaryInterface } from './interfaces'
2
2
 
3
3
  export const eduMetadataDictionary: PillDictionaryInterface = {
4
+ EDUEventPage: {
5
+ variant: 'primary',
6
+ icons: 'primary',
7
+ type: 'event'
8
+ },
4
9
  EDUCollectionsDetailPage: {
5
10
  label: 'Collection',
6
11
  variant: 'primary-inverted',
@@ -25,10 +30,41 @@ export const eduMetadataDictionary: PillDictionaryInterface = {
25
30
  icons: 'primary',
26
31
  type: 'resource'
27
32
  },
28
- EDUEventPage: {
33
+ EDUStudentProjectPage: {
34
+ label: 'Student Project',
35
+ variant: 'secondary',
36
+ icons: 'secondary',
37
+ type: 'resource'
38
+ },
39
+ EDUImageDetailPage: {
40
+ label: 'Image',
29
41
  variant: 'primary',
30
42
  icons: 'primary',
31
- type: 'event'
43
+ type: 'resource'
44
+ },
45
+ EDUInfographicDetailPage: {
46
+ label: 'Infographic',
47
+ variant: 'primary',
48
+ icons: 'primary',
49
+ type: 'resource'
50
+ },
51
+ EDUDocumentDetailPage: {
52
+ label: 'Document',
53
+ variant: 'primary',
54
+ icons: 'primary',
55
+ type: 'resource'
56
+ },
57
+ EDUVideoDetailPage: {
58
+ label: 'Video',
59
+ variant: 'primary',
60
+ icons: 'primary',
61
+ type: 'resource'
62
+ },
63
+ EDUGalleryDetailPage: {
64
+ label: 'Gallery',
65
+ variant: 'secondary',
66
+ icons: 'secondary',
67
+ type: 'resource'
32
68
  }
33
69
  }
34
70
 
@@ -0,0 +1,106 @@
1
+ import { BlockKeyPointsData } from './../../../components/BlockKeyPoints/BlockKeyPoints.stories'
2
+ import { BlockLinkCardCarouselData } from './../../../components/BlockLinkCarousel/BlockLinkCarousel.stories.js'
3
+ import { EventsBlockLinkCarouselData } from './../../../components/BlockLinkCarousel/BlockLinkCarousel.stories'
4
+ import { AboutTheAuthorData } from './../../../components/AboutTheAuthor/AboutTheAuthor.stories'
5
+ import { BlockImageData } from './../../../components/BlockImage/BlockImage.stories'
6
+ import { BlockVideoData } from './../../../components/BlockVideo/BlockVideo.stories'
7
+ import { BlockVideoEmbedData } from './../../../components/BlockVideoEmbed/BlockVideoEmbed.stories'
8
+ import { BlockImageComparisonData } from './../../../components/BlockImageComparison/BlockImageComparison.stories'
9
+ import PageEduGalleryDetail from './PageEduGalleryDetail.vue'
10
+
11
+ export default {
12
+ title: 'Templates/EDU/PageEduGalleryDetail',
13
+ component: PageEduGalleryDetail,
14
+ tags: ['!autodocs'],
15
+ parameters: {
16
+ html: {
17
+ root: '#storyDecorator'
18
+ },
19
+ layout: 'fullscreen'
20
+ },
21
+ excludeStories: /.*Data$/
22
+ }
23
+
24
+ const PageEduGalleryDetailData = {
25
+ title: 'Gallery Detail',
26
+ slug: 'gallery-item',
27
+ url: '/resources/gallery/gallery-item',
28
+ lastPublishedAt: '2024-08-22T02:33:13.507206+00:00',
29
+ thumbnailImage: {
30
+ alt: '',
31
+ original: 'https://picsum.photos/512/288'
32
+ },
33
+ authors: AboutTheAuthorData,
34
+
35
+ body: [
36
+ {
37
+ blockType: 'RichTextBlock',
38
+ value:
39
+ '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p><p>Integer imperdiet blandit neque vitae euismod. Nulla aliquet lacus nibh, vel tincidunt urna efficitur non. In et eros vitae ex posuere maximus quis eget urna. Suspendisse fringilla posuere velit sit amet posuere. Morbi malesuada bibendum vehicula. Donec faucibus ut erat ut mattis. Suspendisse ornare, quam at placerat cursus, dolor mi lacinia nunc, eget maximus augue nulla in dolor.</p>\n'
40
+ }
41
+ ],
42
+ relatedLinks: [
43
+ {
44
+ blockType: 'RelatedLinksBlock',
45
+ heading: 'Related Links',
46
+ links: [
47
+ {
48
+ document: null,
49
+ externalLink: 'http://www.google.com',
50
+ page: null,
51
+ text: 'Lorem ipsum dolor'
52
+ },
53
+ {
54
+ document: null,
55
+ externalLink: 'http://www.google.com',
56
+ page: null,
57
+ text: 'Sit amet consectatur'
58
+ }
59
+ ]
60
+ }
61
+ ],
62
+ relatedContent: EventsBlockLinkCarouselData,
63
+ exploreMore: [...BlockLinkCardCarouselData, ...EventsBlockLinkCarouselData]
64
+ }
65
+ // stories
66
+ export const BaseStory = {
67
+ name: 'PageEduGalleryDetail',
68
+ args: {
69
+ data: {
70
+ __typename: 'EDUGalleryDetailPage',
71
+ ...PageEduGalleryDetailData,
72
+ showJumpMenu: true,
73
+ overviewString: '<p data-block-key="f2dwn">Overview about the gallery.</p>',
74
+ galleryItems: [
75
+ {
76
+ blockId: `${Math.random().toString(36).slice(2)}`,
77
+ heading: 'Gallery Item Heading',
78
+ description:
79
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
80
+ media: [{ ...BlockImageData, blockType: 'ImageBlock' }]
81
+ },
82
+ {
83
+ blockId: `${Math.random().toString(36).slice(2)}`,
84
+ heading: 'Gallery Item Heading',
85
+ description:
86
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
87
+ media: [BlockImageComparisonData]
88
+ },
89
+ {
90
+ blockId: `${Math.random().toString(36).slice(2)}`,
91
+ heading: 'Gallery Item Heading',
92
+ description:
93
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
94
+ media: [BlockVideoData.block]
95
+ },
96
+ {
97
+ blockId: `${Math.random().toString(36).slice(2)}`,
98
+ heading: 'Gallery Item Heading',
99
+ description:
100
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
101
+ media: [BlockVideoEmbedData.data]
102
+ }
103
+ ]
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,238 @@
1
+ <script setup lang="ts">
2
+ import { computed, reactive } from 'vue'
3
+ import {
4
+ PageEduResourcesObject,
5
+ BreadcrumbPathObject,
6
+ StreamfieldBlockData
7
+ } from '../../../interfaces'
8
+ import LayoutHelper from './../../../components/LayoutHelper/LayoutHelper.vue'
9
+ import BaseHeading from './../../../components/BaseHeading/BaseHeading.vue'
10
+ import DetailHeadline from './../../../components/DetailHeadline/DetailHeadline.vue'
11
+ import ShareButtonsEdu from './../../../components/ShareButtonsEdu/ShareButtonsEdu.vue'
12
+ import BlockVideo from './../../../components/BlockVideo/BlockVideo.vue'
13
+ import BlockImageStandard from './../../../components/BlockImage/BlockImageStandard.vue'
14
+ import BlockImageComparison from './../../../components/BlockImageComparison/BlockImageComparison.vue'
15
+ import BlockVideoEmbed from './../../../components/BlockVideoEmbed/BlockVideoEmbed.vue'
16
+ import BlockRelatedLinks from './../../../components/BlockRelatedLinks/BlockRelatedLinks.vue'
17
+ import BlockLinkCarousel from './../../../components/BlockLinkCarousel/BlockLinkCarousel.vue'
18
+ import BlockText from './../../../components/BlockText/BlockText.vue'
19
+ import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
20
+ import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
21
+ import { getHeadingId } from '../../../utils/getHeadingId'
22
+ interface PageEduGalleryObject extends PageEduResourcesObject {
23
+ overviewString?: string
24
+ galleryItems?: {
25
+ blockId: string
26
+ heading?: string
27
+ description?: string
28
+ media: StreamfieldBlockData[]
29
+ }[]
30
+ }
31
+
32
+ interface PageEduGalleryDetailProps {
33
+ data: PageEduGalleryObject
34
+ }
35
+
36
+ // define props
37
+ const props = withDefaults(defineProps<PageEduGalleryDetailProps>(), {
38
+ data: undefined
39
+ })
40
+
41
+ const headingIdGetter = (id: string) => {
42
+ return getHeadingId('galleryItem', id)
43
+ }
44
+
45
+ const jumpMenuHeadings = computed((): BreadcrumbPathObject[] => {
46
+ const items = data.galleryItems
47
+ const itemHeadings: BreadcrumbPathObject[] = []
48
+ if (items) {
49
+ items.forEach((item) => {
50
+ if (item.heading) {
51
+ itemHeadings.push({
52
+ title: item.heading,
53
+ path: '#' + headingIdGetter(item.blockId)
54
+ } as BreadcrumbPathObject)
55
+ }
56
+ })
57
+ }
58
+ return itemHeadings
59
+ })
60
+ const { data } = reactive(props)
61
+ </script>
62
+ <template>
63
+ <div
64
+ v-if="data"
65
+ class="PageEduGalleryDetail ThemeVariantLight pt-5 lg:pt-12"
66
+ itemscope
67
+ itemtype="http://schema.org/MediaGallery"
68
+ >
69
+ <!-- Detail Headline -->
70
+ <LayoutHelper
71
+ indent="col-2"
72
+ class="mb-5 lg:mb-10"
73
+ >
74
+ <DetailHeadline
75
+ :title="data.title"
76
+ label="Slideshow"
77
+ :publication-date="data.publicationDate"
78
+ schema
79
+ pill
80
+ />
81
+ <ShareButtonsEdu
82
+ v-if="data?.url"
83
+ class="mt-4"
84
+ :url="data.url"
85
+ :title="data.title"
86
+ :image="data.thumbnailImage?.original"
87
+ />
88
+ <BlockText
89
+ v-if="data.overviewString"
90
+ :text="data.overviewString"
91
+ class="lg:mt-8 mt-5"
92
+ />
93
+ </LayoutHelper>
94
+
95
+ <NavJumpMenu
96
+ v-if="data.showJumpMenu && jumpMenuHeadings?.length"
97
+ :title="data.title"
98
+ :jump-links="jumpMenuHeadings"
99
+ />
100
+
101
+ <div
102
+ v-for="(item, index) in data.galleryItems"
103
+ :id="headingIdGetter(item.blockId)"
104
+ :key="index"
105
+ class="PageEduGalleryDetailItem"
106
+ >
107
+ <template v-if="item.media?.length">
108
+ <template
109
+ v-for="(block, _media_index) in item.media"
110
+ :key="_media_index"
111
+ >
112
+ <template v-if="block.blockType === 'ImageBlock'">
113
+ <LayoutHelper
114
+ v-if="block.image"
115
+ indent="col-2"
116
+ class="mb-5 lg:mb-10"
117
+ >
118
+ <BlockImageStandard :data="block.image" />
119
+ </LayoutHelper>
120
+ </template>
121
+ <template v-else-if="block.blockType === 'ImageComparisonBlock'">
122
+ <LayoutHelper
123
+ indent="col-2"
124
+ class="mb-5 lg:mb-10"
125
+ >
126
+ <BlockImageComparison :data="block" />
127
+ </LayoutHelper>
128
+ </template>
129
+ <template v-else-if="block.blockType === 'VideoBlock'">
130
+ <LayoutHelper
131
+ indent="col-2"
132
+ class="mb-5 lg:mb-10"
133
+ >
134
+ <BlockVideo :data="block" />
135
+ </LayoutHelper>
136
+ </template>
137
+ <template v-else-if="block.blockType === 'VideoEmbedBlock'">
138
+ <LayoutHelper
139
+ indent="col-2"
140
+ class="mb-5 lg:mb-10"
141
+ >
142
+ <BlockVideoEmbed :data="block" />
143
+ </LayoutHelper>
144
+ </template>
145
+ </template>
146
+ </template>
147
+ <LayoutHelper
148
+ v-if="item.heading || item.description"
149
+ indent="col-3"
150
+ >
151
+ <BaseHeading
152
+ v-if="item.heading"
153
+ level="h2"
154
+ class="mb-3 lg:mb-5"
155
+ >{{ item.heading }}</BaseHeading
156
+ >
157
+ <BlockText
158
+ v-if="item.description"
159
+ :text="item.description"
160
+ />
161
+ </LayoutHelper>
162
+ <LayoutHelper
163
+ indent="col-2"
164
+ class="pt-10 lg:pt-18 mb-10 lg:mb-18"
165
+ >
166
+ <hr class="border-t-0 border-b border-gray-light-mid" />
167
+ </LayoutHelper>
168
+ </div>
169
+
170
+ <!-- related links -->
171
+ <LayoutHelper
172
+ v-if="data.relatedLinks && data.relatedLinks.length"
173
+ indent="col-2"
174
+ class="lg:mb-18 mb-10"
175
+ >
176
+ <BlockRelatedLinks :data="data.relatedLinks[0]" />
177
+ </LayoutHelper>
178
+
179
+ <!-- related content -->
180
+ <BlockLinkCarousel
181
+ item-type="cards"
182
+ class="lg:my-24 my-12 print:px-4"
183
+ :heading="data.relatedContentHeading || 'Related Galleries & Images'"
184
+ :items="data.relatedContent"
185
+ />
186
+
187
+ <LayoutHelper
188
+ v-if="data.authors?.length"
189
+ indent="col-3"
190
+ >
191
+ <AboutTheAuthor :authors="data.authors" />
192
+ </LayoutHelper>
193
+
194
+ <LayoutHelper
195
+ v-if="data.lastPublishedAt"
196
+ indent="col-3"
197
+ class="lg:my-18 my-10"
198
+ >
199
+ <p class="border-t border-gray-light-mid pt-8">
200
+ <strong class="capitalize">Gallery Last Updated:</strong>
201
+ {{
202
+ // @ts-ignore
203
+ $filters.displayDate(data.lastPublishedAt)
204
+ }}
205
+ </p>
206
+ </LayoutHelper>
207
+ <!-- Explore More -->
208
+ <!-- <div
209
+ v-if="data.relatedContent?.length"
210
+ class="bg-stars bg-[#15003B] lg:py-24 lg:mt-24 py-12 mt-12 print:px-4"
211
+ >
212
+ <BlockLinkCarousel
213
+ class="ThemeVariantDark"
214
+ item-type="cards"
215
+ heading="Explore More"
216
+ :items="data.relatedContent"
217
+ />
218
+ </div> -->
219
+ </div>
220
+ </template>
221
+ <style lang="scss">
222
+ .PageEduGalleryDetail {
223
+ .bg-stars .MixinCarousel__Heading {
224
+ @apply text-white;
225
+ }
226
+ .MixinFancybox + .p-4 {
227
+ @apply px-0;
228
+ }
229
+ .PageEduGalleryDetailItem {
230
+ &:target {
231
+ @apply scroll-mt-14;
232
+ @screen lg {
233
+ @apply scroll-mt-[8rem];
234
+ }
235
+ }
236
+ }
237
+ }
238
+ </style>
@@ -181,7 +181,21 @@ export const BaseStory = {
181
181
  steps: [
182
182
  {
183
183
  blocks: [
184
+ // {
185
+ // blockType: 'HeadingBlock',
186
+ // heading: 'Heading Text',
187
+ // level: 'h3',
188
+ // size: 'h3',
189
+ // blockId: `${Math.random().toString(36).slice(2)}`
190
+ // },
184
191
  ...BlockStreamfieldMinimalData.body,
192
+ {
193
+ blockType: 'HeadingBlock',
194
+ heading: 'Heading Text',
195
+ level: 'h3',
196
+ size: 'h3',
197
+ blockId: `${Math.random().toString(36).slice(2)}`
198
+ },
185
199
 
186
200
  {
187
201
  blockType: 'RichTextBlock',
@@ -139,7 +139,7 @@ const anchorId = computed(() => {
139
139
  }
140
140
  .PageEduProcedureSectionSingleStep {
141
141
  li:not(:last-of-type) .BlockStreamfield {
142
- @apply -mb-5 lg:-mb-10;
142
+ @apply -mb-5;
143
143
  }
144
144
  }
145
145
  ol.PageEduProcedureSectionSingleStep {
@@ -148,7 +148,7 @@ const anchorId = computed(() => {
148
148
  @apply relative w-full;
149
149
  counter-increment: step;
150
150
  &::before {
151
- @apply relative block w-[45rem] mx-auto h-0 pl-3;
151
+ @apply relative block w-[45rem] mx-auto h-0 pl-1;
152
152
  content: counter(step) '. ';
153
153
  // mimicking .text-body-lg
154
154
  font-size: pxToRem(18);
@@ -163,13 +163,13 @@ const anchorId = computed(() => {
163
163
  }
164
164
  @screen md {
165
165
  &::before {
166
- @apply w-[50rem];
166
+ @apply w-[51.5rem];
167
167
  font-size: pxToRem(20);
168
168
  }
169
169
  }
170
170
  @screen lg {
171
171
  &::before {
172
- @apply w-[47rem] pl-0;
172
+ @apply w-[46rem] pl-0;
173
173
  font-size: pxToRem(21);
174
174
  }
175
175
  }
@@ -179,6 +179,11 @@ const anchorId = computed(() => {
179
179
  font-size: pxToRem(22);
180
180
  }
181
181
  }
182
+ @screen 2xl {
183
+ &::before {
184
+ // @apply w-[58.5rem];
185
+ }
186
+ }
182
187
  }
183
188
  }
184
189
  }
@@ -0,0 +1,176 @@
1
+ import { BlockKeyPointsData } from './../../../components/BlockKeyPoints/BlockKeyPoints.stories'
2
+ import { BlockLinkCardCarouselData } from './../../../components/BlockLinkCarousel/BlockLinkCarousel.stories.js'
3
+ import { EventsBlockLinkCarouselData } from './../../../components/BlockLinkCarousel/BlockLinkCarousel.stories'
4
+ import { AboutTheAuthorData } from './../../../components/AboutTheAuthor/AboutTheAuthor.stories'
5
+ import { BlockImageData } from './../../../components/BlockImage/BlockImage.stories'
6
+ import { BlockVideoData } from './../../../components/BlockVideo/BlockVideo.stories'
7
+ import { BlockVideoEmbedData } from './../../../components/BlockVideoEmbed/BlockVideoEmbed.stories'
8
+ import { BlockImageComparisonData } from './../../../components/BlockImageComparison/BlockImageComparison.stories'
9
+ import PageEduMultimediaDetail from './PageEduMultimediaDetail.vue'
10
+
11
+ export default {
12
+ title: 'Templates/EDU/PageEduMultimediaDetail',
13
+ component: PageEduMultimediaDetail,
14
+ tags: ['!autodocs'],
15
+ parameters: {
16
+ html: {
17
+ root: '#storyDecorator'
18
+ },
19
+ layout: 'fullscreen'
20
+ },
21
+ excludeStories: /.*Data$/
22
+ }
23
+
24
+ const PageEduMultimediaDetailData = {
25
+ title: 'Media Item',
26
+ slug: 'media-item',
27
+ url: '/resources/media/media-item',
28
+ lastPublishedAt: '2024-08-22T02:33:13.507206+00:00',
29
+ thumbnailImage: {
30
+ alt: '',
31
+ original: 'https://picsum.photos/512/288'
32
+ },
33
+ authors: AboutTheAuthorData,
34
+
35
+ body: [
36
+ {
37
+ blockType: 'RichTextBlock',
38
+ value:
39
+ '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p><p>Integer imperdiet blandit neque vitae euismod. Nulla aliquet lacus nibh, vel tincidunt urna efficitur non. In et eros vitae ex posuere maximus quis eget urna. Suspendisse fringilla posuere velit sit amet posuere. Morbi malesuada bibendum vehicula. Donec faucibus ut erat ut mattis. Suspendisse ornare, quam at placerat cursus, dolor mi lacinia nunc, eget maximus augue nulla in dolor.</p>\n'
40
+ }
41
+ ],
42
+ relatedLinks: [
43
+ {
44
+ blockType: 'RelatedLinksBlock',
45
+ heading: 'Related Links',
46
+ links: [
47
+ {
48
+ document: null,
49
+ externalLink: 'http://www.google.com',
50
+ page: null,
51
+ text: 'Lorem ipsum dolor'
52
+ },
53
+ {
54
+ document: null,
55
+ externalLink: 'http://www.google.com',
56
+ page: null,
57
+ text: 'Sit amet consectatur'
58
+ }
59
+ ]
60
+ }
61
+ ],
62
+ relatedContent: EventsBlockLinkCarouselData,
63
+ exploreMore: [...BlockLinkCardCarouselData, ...EventsBlockLinkCarouselData]
64
+ }
65
+ // stories
66
+ export const BaseStory = {
67
+ name: 'Image',
68
+ args: {
69
+ data: {
70
+ __typename: 'EDUImageDetailPage',
71
+ ...PageEduMultimediaDetailData,
72
+ imageAsHero: BlockImageData.image,
73
+ heroImageCaption: 'This is the hero image caption'
74
+ }
75
+ }
76
+ }
77
+
78
+ export const Infographic = {
79
+ args: {
80
+ data: {
81
+ __typename: 'EDUInfographicDetailPage',
82
+ ...PageEduMultimediaDetailData,
83
+ imageAsHero: BlockImageData.image,
84
+ heroImageCaption: 'This is the hero image caption for the infographic'
85
+ }
86
+ }
87
+ }
88
+
89
+ export const Video = {
90
+ args: {
91
+ data: {
92
+ __typename: 'EDUVideoDetailPage',
93
+ ...PageEduMultimediaDetailData,
94
+ video: [BlockVideoData.block],
95
+ transcript: `<p>Preparing to Land Perseverance</p>
96
+ <p>The following tests, conducted from 2017-2020, helped prepare NASA's Perseverance rover for its landing on Mars.</p>
97
+ <p>[music]</p>
98
+ <p>Centrifuge Spin Test</p>`
99
+ }
100
+ }
101
+ }
102
+
103
+ export const VideoEmbed = {
104
+ args: {
105
+ data: {
106
+ __typename: 'EDUVideoDetailPage',
107
+ ...PageEduMultimediaDetailData,
108
+ video: [BlockVideoEmbedData.data],
109
+ transcript: `<p>Preparing to Land Perseverance</p>
110
+ <p>The following tests, conducted from 2017-2020, helped prepare NASA's Perseverance rover for its landing on Mars.</p>
111
+ <p>[music]</p>
112
+ <p>Centrifuge Spin Test</p>
113
+ <p>Santa Clarita, CA June 2019</p>
114
+ <p>[music]</p>
115
+ <p>Parachute Firing Test</p>
116
+ <p>Moses Lake, WA May 2019</p>
117
+ <p>[music]</p>
118
+ <p>[mortar firing]</p>
119
+ <p>[mortar firing]</p>
120
+ <p>[clapping]</p>`
121
+ }
122
+ }
123
+ }
124
+
125
+ export const Document = {
126
+ args: {
127
+ data: {
128
+ __typename: 'EDUDocumentDetailPage',
129
+ ...PageEduMultimediaDetailData,
130
+ heroImage: {
131
+ ...BlockImageData.image
132
+ },
133
+ heroImageCaption: 'This is the hero image caption for the document',
134
+ document: {
135
+ url: 'https://jpl.nasa.gov'
136
+ },
137
+ credit: '<p>Document credit attribution</p>'
138
+ }
139
+ }
140
+ }
141
+
142
+ export const Gallery = {
143
+ args: {
144
+ data: {
145
+ __typename: 'EDUGalleryDetailPage',
146
+ ...PageEduMultimediaDetailData,
147
+ galleryItems: [
148
+ {
149
+ heading: 'Gallery Item Heading',
150
+ description:
151
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
152
+ media: [BlockImageData.image]
153
+ },
154
+ {
155
+ heading: 'Gallery Item Heading',
156
+ description:
157
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
158
+ media: [BlockImageComparisonData]
159
+ },
160
+ {
161
+ heading: 'Gallery Item Heading',
162
+ description:
163
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
164
+ media: [BlockVideoData.block]
165
+ },
166
+ {
167
+ heading: 'Gallery Item Heading',
168
+ description:
169
+ '<p data-block-key="53wg6">Description that is <strong>rich text</strong>.</p>',
170
+ media: [BlockVideoEmbedData.data]
171
+ }
172
+ ],
173
+ showJumpMenu: true
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,434 @@
1
+ <script setup lang="ts">
2
+ import { computed, reactive } from 'vue'
3
+ import { PageEduResourcesObject, ImageObject } from '../../../interfaces'
4
+ import LayoutHelper from './../../../components/LayoutHelper/LayoutHelper.vue'
5
+ import BaseHeading from './../../../components/BaseHeading/BaseHeading.vue'
6
+ import DetailHeadline from './../../../components/DetailHeadline/DetailHeadline.vue'
7
+ import ShareButtonsEdu from './../../../components/ShareButtonsEdu/ShareButtonsEdu.vue'
8
+ import BaseVideo from './../../../components/BaseVideo/BaseVideo.vue'
9
+ import BlockImageStandard from './../../../components/BlockImage/BlockImageStandard.vue'
10
+ import BlockVideoEmbed from './../../../components/BlockVideoEmbed/BlockVideoEmbed.vue'
11
+ import BaseButton from './../../../components/BaseButton/BaseButton.vue'
12
+ import BlockStreamfield from './../../../components/BlockStreamfield/BlockStreamfield.vue'
13
+ import BaseImagePlaceholder from './../../../components/BaseImagePlaceholder/BaseImagePlaceholder.vue'
14
+ import BaseImage from './../../../components/BaseImage/BaseImage.vue'
15
+ import BlockRelatedLinks from './../../../components/BlockRelatedLinks/BlockRelatedLinks.vue'
16
+ import BlockLinkCarousel from './../../../components/BlockLinkCarousel/BlockLinkCarousel.vue'
17
+ import BlockText from './../../../components/BlockText/BlockText.vue'
18
+ import MixinFancybox from './../../../components/MixinFancybox/MixinFancybox.vue'
19
+ import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
20
+
21
+ interface PageEduMultimediaObject extends PageEduResourcesObject {
22
+ heroImage?: ImageObject
23
+ imageAsHero?: ImageObject
24
+ heroImageCaption?: string
25
+ video?: any
26
+ document?: {
27
+ url: string
28
+ }
29
+ galleryItems?: {
30
+ heading?: string
31
+ description?: string
32
+ media: any[]
33
+ }[]
34
+ credit?: string
35
+ transcript?: string
36
+ }
37
+
38
+ interface PageEduMultimediaDetailProps {
39
+ data: PageEduMultimediaObject
40
+ }
41
+
42
+ // define props
43
+ const props = withDefaults(defineProps<PageEduMultimediaDetailProps>(), {
44
+ data: undefined
45
+ })
46
+
47
+ const typeMapping: {
48
+ [key: string]: {
49
+ type: string
50
+ label: string
51
+ schema: string
52
+ relatedContentHeading: string
53
+ }
54
+ } = {
55
+ EDUImageDetailPage: {
56
+ type: 'image',
57
+ label: 'image',
58
+ schema: 'http://schema.org/ImageObject',
59
+ relatedContentHeading: 'Related Images & Galleries'
60
+ },
61
+ EDUInfographicDetailPage: {
62
+ type: 'image',
63
+ label: 'infographic',
64
+ schema: 'http://schema.org/ImageObject',
65
+ relatedContentHeading: 'Related Images & Galleries'
66
+ },
67
+ EDUVideoDetailPage: {
68
+ type: 'video',
69
+ label: 'video',
70
+ schema: 'http://schema.org/VideoObject',
71
+ relatedContentHeading: 'Related Videos'
72
+ },
73
+ EDUGalleryDetailPage: {
74
+ type: 'gallery',
75
+ label: 'gallery',
76
+ schema: 'http://schema.org/ImageGallery',
77
+ relatedContentHeading: ''
78
+ },
79
+ EDUDocumentDetailPage: {
80
+ type: 'document',
81
+ label: 'document',
82
+ schema: 'http://schema.org/DigitalDocument',
83
+ relatedContentHeading: 'Related Documents'
84
+ }
85
+ }
86
+ const mediaType = computed(() => {
87
+ const type = data.__typename
88
+ if (type) {
89
+ return typeMapping[type]?.type
90
+ }
91
+ return undefined
92
+ })
93
+
94
+ const mediaLabel = computed(() => {
95
+ const type = data.__typename
96
+ if (type) {
97
+ return typeMapping[type]?.label
98
+ }
99
+ return undefined
100
+ })
101
+
102
+ const schemaType = computed(() => {
103
+ const type = data.__typename
104
+ if (type) {
105
+ return typeMapping[type]?.schema
106
+ }
107
+ return undefined
108
+ })
109
+
110
+ const heroImage = computed(() => {
111
+ switch (mediaType.value) {
112
+ case 'image':
113
+ return data.imageAsHero
114
+ case 'document':
115
+ return data.heroImage
116
+ default:
117
+ return undefined
118
+ }
119
+ })
120
+
121
+ const videoBlock = computed(() => {
122
+ if (mediaType.value === 'video' && data.video?.length) {
123
+ return data.video[0]
124
+ }
125
+ return undefined
126
+ })
127
+
128
+ const downloadUrl = computed(() => {
129
+ switch (mediaType.value) {
130
+ case 'image':
131
+ return heroImage.value?.original
132
+ case 'video':
133
+ return videoBlock.value?.video?.file
134
+ case 'document':
135
+ return data.document?.url
136
+ default:
137
+ return undefined
138
+ }
139
+ })
140
+
141
+ const creditText = computed(() => {
142
+ switch (mediaType.value) {
143
+ case 'image':
144
+ return heroImage.value?.credit
145
+ case 'video':
146
+ return videoBlock.value?.caption
147
+ case 'document':
148
+ return data.credit
149
+ default:
150
+ return undefined
151
+ }
152
+ })
153
+
154
+ const relatedContentHeading = computed(() => {
155
+ const type = data.__typename
156
+ let text = data.relatedContentHeading
157
+ if (type && !text) {
158
+ text = typeMapping[type]?.relatedContentHeading
159
+ }
160
+ return text
161
+ })
162
+
163
+ const { data } = reactive(props)
164
+ </script>
165
+ <template>
166
+ <div
167
+ v-if="data && mediaType"
168
+ class="PageEduMultimediaDetail ThemeVariantLight pt-5 lg:pt-12"
169
+ itemscope
170
+ :itemtype="schemaType"
171
+ >
172
+ <!-- Detail Headline -->
173
+ <LayoutHelper
174
+ indent="col-2"
175
+ class="mb-10"
176
+ >
177
+ <DetailHeadline
178
+ :title="data.title"
179
+ :label="mediaLabel"
180
+ :publication-date="data.publicationDate"
181
+ schema
182
+ pill
183
+ />
184
+ <ShareButtonsEdu
185
+ v-if="data?.url"
186
+ class="mt-4"
187
+ :url="data.url"
188
+ :title="data.title"
189
+ :image="data.thumbnailImage?.original"
190
+ />
191
+ </LayoutHelper>
192
+
193
+ <!-- Media-specific content -->
194
+ <template v-if="mediaType === 'image'">
195
+ <!-- schema.org -->
196
+ <meta
197
+ v-if="heroImage?.original"
198
+ itemprop="contentUrl"
199
+ :content="heroImage.original"
200
+ />
201
+ <meta
202
+ v-if="heroImage?.src"
203
+ itemprop="thumbnailUrl"
204
+ :content="heroImage.src?.url"
205
+ />
206
+ <meta
207
+ v-if="heroImage?.credit"
208
+ itemprop="creditText"
209
+ :content="heroImage.credit"
210
+ />
211
+
212
+ <div class="max-w-screen-3xl lg:mb-24 mx-auto mt-10 mb-8">
213
+ <MixinFancybox
214
+ v-if="heroImage"
215
+ :src="heroImage.original || heroImage.src?.url"
216
+ :caption="data.heroImageCaption"
217
+ :credit="heroImage.credit"
218
+ :detail-url="heroImage.detailUrl"
219
+ >
220
+ <BaseImagePlaceholder
221
+ class="relative bg-black border border-black"
222
+ aspect-ratio="21:9"
223
+ >
224
+ <BaseImage
225
+ v-if="heroImage.src"
226
+ :src="heroImage.src.url"
227
+ :srcset="heroImage.srcSet"
228
+ :alt="heroImage.alt"
229
+ :width="heroImage.src.width"
230
+ :height="heroImage.src.height"
231
+ object-fit-class="scaleDown"
232
+ loading="eager"
233
+ />
234
+ </BaseImagePlaceholder>
235
+ </MixinFancybox>
236
+ </div>
237
+ </template>
238
+ <template v-else-if="mediaType === 'video' && data.video?.length">
239
+ <meta
240
+ v-if="videoBlock.video?.file"
241
+ itemprop="contentUrl"
242
+ :content="videoBlock.video.file"
243
+ />
244
+ <meta
245
+ v-if="videoBlock.video?.duration"
246
+ itemprop="duration"
247
+ :content="videoBlock.video.duration"
248
+ />
249
+ <meta
250
+ v-if="data.thumbnailImage && data.thumbnailImage.original"
251
+ itemprop="thumbnailUrl"
252
+ :content="data.thumbnailImage.original"
253
+ />
254
+ <meta
255
+ v-if="videoBlock.caption"
256
+ itemprop="description"
257
+ :content="videoBlock.caption"
258
+ />
259
+ <meta
260
+ v-if="videoBlock.credit"
261
+ itemprop="creditText"
262
+ :content="videoBlock.credit"
263
+ />
264
+ <template v-if="videoBlock.blockType === 'VideoBlock' && videoBlock.video">
265
+ <div class="max-w-screen-2xl lg:mb-24 mx-auto mt-10 mb-8">
266
+ <BaseVideo
267
+ :data="videoBlock.video"
268
+ schema
269
+ />
270
+ </div>
271
+ </template>
272
+ <template v-else-if="videoBlock.blockType === 'VideoEmbedBlock'">
273
+ <div
274
+ v-if="videoBlock.embed"
275
+ class="max-w-screen-2xl lg:mb-24 mx-auto mt-10 mb-8"
276
+ >
277
+ <BlockVideoEmbed :data="videoBlock" />
278
+ </div>
279
+ </template>
280
+ </template>
281
+ <template v-if="mediaType === 'document'">
282
+ <!-- schema.org -->
283
+ <meta
284
+ v-if="data.document?.url"
285
+ itemprop="contentUrl"
286
+ :content="data.document.url"
287
+ />
288
+ <meta
289
+ v-if="data.thumbnailImage?.original"
290
+ itemprop="thumbnailUrl"
291
+ :content="data.thumbnailImage.original"
292
+ />
293
+ <meta
294
+ v-if="data?.credit"
295
+ itemprop="creditText"
296
+ :content="data.credit"
297
+ />
298
+
299
+ <div class="max-w-screen-3xl lg:mb-24 mx-auto mt-10 mb-8">
300
+ <!-- inline hero content -->
301
+ <LayoutHelper
302
+ v-if="heroImage"
303
+ indent="col-2"
304
+ class="lg:mb-22 mt-10 mb-10"
305
+ >
306
+ <BlockImageStandard
307
+ :data="heroImage"
308
+ :caption="data.heroImageCaption"
309
+ />
310
+ </LayoutHelper>
311
+ </div>
312
+ </template>
313
+
314
+ <!-- !Gallery body -->
315
+
316
+ <LayoutHelper indent="col-2">
317
+ <div class="lg:grid grid-cols-12">
318
+ <div
319
+ v-if="data.body?.length || data.transcript"
320
+ class="col-span-8"
321
+ >
322
+ <BlockStreamfield
323
+ v-if="data.body?.length"
324
+ variant="fluid"
325
+ :data="data.body"
326
+ />
327
+ <hr
328
+ v-if="data.body?.length && data.transcript"
329
+ class="border-gray-light-mid lg:mb-8 mb-5"
330
+ />
331
+ <div
332
+ v-if="data.transcript"
333
+ class="lg:mb-22 mb-10"
334
+ >
335
+ <BaseHeading
336
+ level="h2"
337
+ class="mb-5"
338
+ >Transcript</BaseHeading
339
+ >
340
+ <BlockText
341
+ :text="data.transcript"
342
+ variant="medium"
343
+ class="audio-transcript"
344
+ itemprop="transcript"
345
+ />
346
+ </div>
347
+ </div>
348
+ <aside class="col-start-10 col-end-13">
349
+ <div class="lg:pt-0 pt-8 mb-12">
350
+ <div
351
+ v-if="downloadUrl"
352
+ class="lg:w-auto w-full"
353
+ >
354
+ <BaseButton
355
+ :href="downloadUrl"
356
+ class="w-full mb-5"
357
+ variant="primary"
358
+ compact
359
+ >
360
+ Download {{ mediaLabel }}
361
+ </BaseButton>
362
+ </div>
363
+ </div>
364
+
365
+ <div
366
+ v-if="creditText"
367
+ class="lg:mb-16 mb-8"
368
+ >
369
+ <span class="font-secondary w-full text-base tracking-wider uppercase"> Credit </span>
370
+ <BlockText :text="creditText" />
371
+ </div>
372
+ </aside>
373
+ </div>
374
+ </LayoutHelper>
375
+
376
+ <!-- UNIVERSAL -->
377
+ <!-- related links -->
378
+ <LayoutHelper
379
+ v-if="data.relatedLinks && data.relatedLinks.length"
380
+ indent="col-2"
381
+ class="lg:mb-18 mb-10"
382
+ >
383
+ <BlockRelatedLinks :data="data.relatedLinks[0]" />
384
+ </LayoutHelper>
385
+
386
+ <!-- related content -->
387
+ <BlockLinkCarousel
388
+ item-type="cards"
389
+ class="lg:my-24 my-12 print:px-4"
390
+ :heading="relatedContentHeading"
391
+ :items="data.relatedContent"
392
+ />
393
+
394
+ <LayoutHelper
395
+ v-if="data.authors?.length"
396
+ indent="col-3"
397
+ >
398
+ <AboutTheAuthor :authors="data.authors" />
399
+ </LayoutHelper>
400
+
401
+ <LayoutHelper
402
+ v-if="data.lastPublishedAt"
403
+ indent="col-3"
404
+ class="lg:my-18 my-10"
405
+ >
406
+ <p class="border-t border-gray-light-mid pt-8">
407
+ <strong class="capitalize">{{ mediaLabel }} Last Updated:</strong>
408
+ {{
409
+ // @ts-ignore
410
+ $filters.displayDate(data.lastPublishedAt)
411
+ }}
412
+ </p>
413
+ </LayoutHelper>
414
+ <!-- Explore More -->
415
+ <!-- <div
416
+ v-if="data.relatedContent?.length"
417
+ class="bg-stars bg-[#15003B] lg:py-24 lg:mt-24 py-12 mt-12 print:px-4"
418
+ >
419
+ <BlockLinkCarousel
420
+ class="ThemeVariantDark"
421
+ item-type="cards"
422
+ heading="Explore More"
423
+ :items="data.relatedContent"
424
+ />
425
+ </div> -->
426
+ </div>
427
+ </template>
428
+ <style lang="scss">
429
+ .PageEduMultimediaDetail {
430
+ .bg-stars .MixinCarousel__Heading {
431
+ @apply text-white;
432
+ }
433
+ }
434
+ </style>
@@ -1,5 +1,4 @@
1
1
  import { camelCase } from 'lodash'
2
- import { type HeadingLevel } from '../components/BaseHeading/BaseHeading.vue'
3
- export const getHeadingId = (heading: HeadingLevel, blockId?: string) => {
2
+ export const getHeadingId = (heading: string, blockId?: string) => {
4
3
  return 'anchor_' + camelCase(heading) + (blockId ? '_' + camelCase(blockId) : '')
5
4
  }