@explorer-1/vue 0.1.7 → 0.1.9

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 (30) hide show
  1. package/dist/explorer-1-vue.js +4266 -4261
  2. package/dist/explorer-1-vue.umd.cjs +12 -12
  3. package/dist/src/components/BlockStreamfield/BlockStreamfield.stories.d.ts +1 -1
  4. package/dist/src/components/BlockVideoEmbed/BlockVideoEmbed.stories.d.ts +1 -0
  5. package/dist/src/components/HomepageEmbedBlock/HomepageEmbedBlock.stories.d.ts +1 -0
  6. package/dist/src/templates/www/PageAsteroidWatchIndex/PageAsteroidWatchIndex.stories.d.ts +1 -1
  7. package/dist/src/templates/www/PageHomepage/PageHomepage.stories.d.ts +1 -0
  8. package/dist/style.css +1 -1
  9. package/package.json +1 -1
  10. package/src/components/BlockImage/BlockImageFullBleed.vue +1 -1
  11. package/src/components/BlockImage/BlockImageStandard.vue +1 -1
  12. package/src/components/BlockImageCarousel/BlockImageCarousel.stories.js +1 -1
  13. package/src/components/BlockImageCarousel/BlockImageCarousel.vue +1 -1
  14. package/src/components/BlockImageCarouselItem/BlockImageCarouselItem.vue +1 -1
  15. package/src/components/BlockImageGallery/BlockImageGallery.vue +1 -1
  16. package/src/components/BlockInlineImage/BlockInlineImage.vue +41 -39
  17. package/src/components/BlockLinkCard/BlockLinkCard.vue +1 -1
  18. package/src/components/BlockLinkTile/BlockLinkTile.vue +1 -1
  19. package/src/components/BlockStreamfield/BlockStreamfield.vue +0 -1
  20. package/src/components/DetailHeadline/DetailHeadline.stories.js +20 -0
  21. package/src/components/DetailHeadline/DetailHeadline.vue +45 -12
  22. package/src/components/NavSecondary/NavSecondary.vue +8 -2
  23. package/src/components/ShareButtonsEdu/ShareButtonsEdu.vue +6 -1
  24. package/src/templates/PageImageDetail/PageImageDetail.stories.js +5 -1
  25. package/src/templates/PageImageDetail/PageImageDetail.vue +1 -1
  26. package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.stories.js +9 -1
  27. package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.vue +16 -13
  28. package/src/templates/www/PageInfographicDetail/PageInfographicDetail.vue +1 -1
  29. package/src/utils/filters.js +2 -1
  30. package/src/utils/mixins.ts +5 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorer-1/vue",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -84,7 +84,7 @@ export default defineComponent({
84
84
  <div class="max-w-screen-3xl mx-auto">
85
85
  <MixinFancybox
86
86
  v-if="theData.src"
87
- :src="theData.original"
87
+ :src="theData.original || theData.src?.url"
88
88
  :caption="theData.caption"
89
89
  :credit="theData.credit"
90
90
  :detail-url="theData.detailUrl"
@@ -74,7 +74,7 @@ export default defineComponent({
74
74
  <div v-if="theData">
75
75
  <MixinFancybox
76
76
  v-if="theData.src"
77
- :src="theData.original"
77
+ :src="theData.original || theData.src?.url"
78
78
  :caption="theData.caption"
79
79
  :credit="theData.credit"
80
80
  :detail-url="theData.detailUrl"
@@ -99,7 +99,7 @@ export const BlockImageCarouselData = [
99
99
 
100
100
  // stories
101
101
  export const BaseStory = {
102
- name: 'BlockImageCarousel',
102
+ name: 'CarouselBlock',
103
103
  args: {
104
104
  blockId: 'ev106po56n',
105
105
  showTitle: false,
@@ -170,7 +170,7 @@ export default defineComponent({
170
170
  return false
171
171
  },
172
172
  itemsMobileNav(): Partial<ImageObject>[] | undefined {
173
- const navArray = this.items
173
+ const navArray = this.items ? this.items.map((item) => item) : undefined
174
174
  if (navArray && this.hasCover) {
175
175
  navArray.push({ cover: 'hasCover' })
176
176
  return navArray
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div v-if="theImageData">
3
3
  <MixinFancybox
4
- :src="theImageData.original"
4
+ :src="theImageData.original || theImageData.src?.url"
5
5
  :caption="theImageData.caption"
6
6
  :credit="theImageData.credit"
7
7
  :detail-url="theImageData.detailUrl"
@@ -10,7 +10,7 @@
10
10
  <template #firstSlide>
11
11
  <MixinFancybox
12
12
  v-if="cover"
13
- :src="cover.original"
13
+ :src="cover.original || cover.src?.url"
14
14
  :caption="description"
15
15
  :credit="cover.credit"
16
16
  :detail-url="cover.detailUrl"
@@ -1,49 +1,51 @@
1
1
  <template>
2
2
  <div
3
3
  v-if="data"
4
- class="BlockInlineImage lg:BaseGrid container mx-auto"
4
+ class="BlockInlineImage container mx-auto"
5
5
  >
6
- <!-- the image -->
7
- <div
8
- v-if="theImageData"
9
- class="lg:mb-0 lg:w-full sm:w-xl lg:mt-0 lg:pr-4 2xl:pr-0 col-span-5 mx-auto mt-8 mb-8"
10
- :class="data.alignTo === 'right' ? 'col-start-8 lg:order-2' : 'col-start-1 lg:order-1'"
11
- >
12
- <!-- should accommodate any size/shape image without cropping -->
13
- <MixinFancybox
6
+ <div class="lg:BaseGrid lg:px-0 px-4">
7
+ <!-- the image -->
8
+ <div
14
9
  v-if="theImageData"
15
- :src="theImageData.original"
16
- :caption="theImageData.caption"
17
- :credit="theImageData.credit"
18
- :detail-url="theImageData.detailUrl"
10
+ class="lg:mb-0 lg:w-full sm:w-xl lg:mt-0 lg:pr-4 2xl:pr-0 col-span-5 mx-auto mt-8 mb-8"
11
+ :class="data.alignTo === 'right' ? 'col-start-8 lg:order-2' : 'col-start-1 lg:order-1'"
19
12
  >
20
- <BaseImagePlaceholder aspect-ratio="none">
21
- <BaseImage
22
- v-if="theImageData && theImageData.src"
23
- :src="theImageData.src.url"
24
- :srcset="theSrcSet"
25
- :width="theImageData.src.width"
26
- :height="theImageData.src.height"
27
- image-class="w-full h-auto"
28
- :alt="theImageData.alt"
29
- loading="lazy"
30
- />
31
- </BaseImagePlaceholder>
32
- </MixinFancybox>
33
- <BaseImageCaption
34
- v-if="hasCaptionArea"
35
- class="lg:mt-3 mt-2"
36
- :data="theImageData"
37
- />
38
- </div>
13
+ <!-- should accommodate any size/shape image without cropping -->
14
+ <MixinFancybox
15
+ v-if="theImageData"
16
+ :src="theImageData.original || theImageData.src?.url"
17
+ :caption="theImageData.caption"
18
+ :credit="theImageData.credit"
19
+ :detail-url="theImageData.detailUrl"
20
+ >
21
+ <BaseImagePlaceholder aspect-ratio="none">
22
+ <BaseImage
23
+ v-if="theImageData && theImageData.src"
24
+ :src="theImageData.src.url"
25
+ :srcset="theSrcSet"
26
+ :width="theImageData.src.width"
27
+ :height="theImageData.src.height"
28
+ image-class="w-full h-auto"
29
+ :alt="theImageData.alt"
30
+ loading="lazy"
31
+ />
32
+ </BaseImagePlaceholder>
33
+ </MixinFancybox>
34
+ <BaseImageCaption
35
+ v-if="hasCaptionArea"
36
+ class="lg:mt-3 mt-2"
37
+ :data="theImageData"
38
+ />
39
+ </div>
39
40
 
40
- <!-- the text -->
41
- <div
42
- v-if="data.text"
43
- class="flex col-span-5"
44
- :class="data.alignTo === 'right' ? 'col-start-3 lg:order-1' : 'col-start-6 lg:order-2'"
45
- >
46
- <BlockText :text="data.text" />
41
+ <!-- the text -->
42
+ <div
43
+ v-if="data.text"
44
+ class="flex col-span-5"
45
+ :class="data.alignTo === 'right' ? 'col-start-3 lg:order-1' : 'col-start-6 lg:order-2'"
46
+ >
47
+ <BlockText :text="data.text" />
48
+ </div>
47
49
  </div>
48
50
  </div>
49
51
  </template>
@@ -58,7 +58,7 @@
58
58
 
59
59
  <component
60
60
  :is="headingLevel || 'p'"
61
- class="text-gray-dark text-xl font-medium leading-tight tracking-tight"
61
+ class="text-gray-dark text-xl font-medium leading-tight tracking-tight edu:font-extrabold"
62
62
  :class="{ 'lg:text-3xl': !compact }"
63
63
  >
64
64
  {{ theItem.title }}
@@ -59,7 +59,7 @@
59
59
  </p>
60
60
  <component
61
61
  :is="headingLevel || 'p'"
62
- class="text-xl leading-tight tracking-tight transition-all duration-200 ease-in delay-200"
62
+ class="text-xl leading-tight tracking-tight transition-all duration-200 ease-in delay-200 edu:font-extrabold"
63
63
  :class="
64
64
  compact
65
65
  ? 'font-semibold mb-0 lg:group-hover:mb-1'
@@ -28,7 +28,6 @@
28
28
  <BlockInlineImage
29
29
  v-else-if="block.blockType == 'InlineImageBlock'"
30
30
  :key="`inlineImageBlock${index}`"
31
- class="lg:px-0 px-4"
32
31
  :class="seamlessText(index) ? 'lg:mb-8 mb-5' : 'lg:mb-18 mb-10'"
33
32
  :data="block"
34
33
  />
@@ -30,6 +30,26 @@ export const BaseStory = {
30
30
  args: DetailHeadlineData
31
31
  }
32
32
 
33
+ export const MultipleAuthors = {
34
+ args: {
35
+ ...DetailHeadlineData,
36
+ author: [
37
+ {
38
+ author: {
39
+ name: 'Author Name',
40
+ organization: 'Organization'
41
+ }
42
+ },
43
+ {
44
+ author: {
45
+ name: 'Another Author',
46
+ organization: 'Organization'
47
+ }
48
+ }
49
+ ]
50
+ }
51
+ }
52
+
33
53
  export const NoAuthor = {
34
54
  args: {
35
55
  title: "NASA's Ingenuity Mars Helicopter Recharges Its Batteries in Flight",
@@ -46,18 +46,30 @@
46
46
  >{{ title }}
47
47
  </BaseHeading>
48
48
  <div
49
- v-if="author || publicationDate"
49
+ v-if="authors?.length || publicationDate"
50
50
  class="lg:text-base text-gray-mid-dark divide-gray-mid-dark px-3 mt-5 -ml-3 text-sm leading-normal"
51
51
  >
52
52
  <span
53
- v-if="author"
53
+ v-if="authors?.length"
54
54
  :itemprop="schema ? 'author' : undefined"
55
55
  itemscope
56
56
  itemtype="https://schema.org/Person"
57
57
  class="pr-3 border-r mr-2"
58
58
  >
59
59
  Written by
60
- <span :itemprop="schema ? 'name' : undefined">{{ author.name }}</span>
60
+ <template
61
+ v-for="(a, index) of authors"
62
+ :key="index"
63
+ >
64
+ <span
65
+ class="inline-block"
66
+ :itemprop="schema ? 'name' : undefined"
67
+ >{{ a.name }}</span
68
+ >
69
+ <template v-if="index !== authors.length - 1"
70
+ ><span class="inline-block pr-1">,</span></template
71
+ >
72
+ </template>
61
73
  </span>
62
74
  <span
63
75
  v-else
@@ -87,7 +99,7 @@
87
99
  import { defineComponent, type PropType } from 'vue'
88
100
  import { mapStores } from 'pinia'
89
101
  import { useThemeStore } from '../../store/theme'
90
- import type { Topic } from './../../interfaces'
102
+ import type { Topic, AuthorObject } from './../../interfaces'
91
103
  import BaseLink from './../BaseLink/BaseLink.vue'
92
104
  import BaseHeading from './../BaseHeading/BaseHeading.vue'
93
105
 
@@ -100,32 +112,39 @@ export default defineComponent({
100
112
  props: {
101
113
  title: {
102
114
  type: String,
103
- required: false
115
+ required: false,
116
+ default: undefined
104
117
  },
105
118
  author: {
106
- type: Object,
107
- required: false
119
+ type: Object as PropType<AuthorObject | AuthorObject[]>,
120
+ required: false,
121
+ default: undefined
108
122
  },
109
123
  publicationDate: {
110
124
  type: String,
111
- required: false
125
+ required: false,
126
+ default: undefined
112
127
  },
113
128
  publicationTime: {
114
129
  type: String,
115
- required: false
130
+ required: false,
131
+ default: undefined
116
132
  },
117
133
  topics: {
118
134
  type: Array as PropType<Topic[]>,
119
- required: false
135
+ required: false,
136
+ default: undefined
120
137
  },
121
138
  // if topics array isn't available
122
139
  label: {
123
140
  type: String,
124
- required: false
141
+ required: false,
142
+ default: undefined
125
143
  },
126
144
  labelLink: {
127
145
  type: String,
128
- required: false
146
+ required: false,
147
+ default: undefined
129
148
  },
130
149
  schema: {
131
150
  type: Boolean,
@@ -138,6 +157,20 @@ export default defineComponent({
138
157
  const currentTime = this.publicationTime || '00:00:00'
139
158
  const returnDate = new Date(this.publicationDate + ' ' + currentTime)
140
159
  return returnDate.toISOString()
160
+ },
161
+ authors(): { name: string; organization: string }[] | undefined {
162
+ let authors: AuthorObject[] | undefined = undefined
163
+ if (this.author && this.author.constructor === Array) {
164
+ authors = []
165
+ // @ts-expect-error we know it's an array at this point
166
+ this.author.forEach((author: { author: AuthorObject }) => {
167
+ // @ts-expect-error authors array is defined above
168
+ authors.push(author.author)
169
+ })
170
+ } else if (this.author) {
171
+ authors = [this.author] as AuthorObject[]
172
+ }
173
+ return authors
141
174
  }
142
175
  }
143
176
  })
@@ -8,7 +8,7 @@
8
8
  >
9
9
  <div class="max-w-screen-3xl mx-auto">
10
10
  <div
11
- class="nav-secondary-container lg:container lg:px-0 lg:whitespace-normal border-gray-mid text-gray-mid-dark lg:overflow-visible relative px-4 pb-0 mx-auto overflow-x-auto text-sm font-medium whitespace-nowrap border-t border-opacity-50"
11
+ class="nav-secondary-container lg:container lg:px-0 lg:whitespace-normal border-gray-mid text-gray-mid-dark lg:overflow-visible relative px-4 pb-0 mx-auto overflow-x-auto text-sm font-medium whitespace-nowrap border-t border-opacity-50 edu:border-0"
12
12
  >
13
13
  <div class="lg:ml-0 2xl:-mr-3 lg:justify-end flex -ml-3">
14
14
  <template v-for="(item, index) in theBreadcrumb">
@@ -139,7 +139,7 @@ export default defineComponent({
139
139
  <style lang="scss">
140
140
  .NavSecondary {
141
141
  top: -1px; // for intersection observer to work
142
- @apply sticky z-50 w-full bg-white border-b edu:border-0 border-gray-mid border-opacity-0 transition-border-opacity duration-150 ease-in;
142
+ @apply sticky z-40 w-full bg-white border-b edu:border-0 border-gray-mid border-opacity-0 transition-border-opacity duration-150 edu:duration-300 ease-in;
143
143
  @apply hidden;
144
144
  @screen lg {
145
145
  @apply block;
@@ -188,4 +188,10 @@ export default defineComponent({
188
188
  }
189
189
  }
190
190
  }
191
+ // since we depend on a body class, the edu: prefix won't work as usual and requires the below line
192
+ body.header-sticky-showing .ThemeEdu .NavSecondary {
193
+ @screen lg {
194
+ @apply top-[4.45rem];
195
+ }
196
+ }
191
197
  </style>
@@ -68,6 +68,11 @@ const twitterLink = computed((): string => {
68
68
  const pinterestLink = computed(() => {
69
69
  return `http://pinterest.com/pin/create/button/?url=${encodedURL.value}&media=${props.image}&description=${encodedTitle.value}`
70
70
  })
71
+
72
+ const googleClassroomLink = computed(() => {
73
+ return `https://classroom.google.com/share?url=${encodedURL.value}`
74
+ })
75
+
71
76
  const mailLink = computed((): string => {
72
77
  return `mailto:?body=${encodedTitle.value}:%20${encodedURL.value}&subject=${encodedTitle.value}`
73
78
  })
@@ -178,7 +183,7 @@ const buttonClass = computed(() => {
178
183
 
179
184
  <BaseButton
180
185
  variant="social"
181
- href="#"
186
+ :href="googleClassroomLink"
182
187
  aria-label="Google Classroom"
183
188
  target="_blank"
184
189
  rel="noopener"
@@ -58,7 +58,11 @@ export const ImageDetailPageData = {
58
58
  }
59
59
  ],
60
60
  keepExploringInstrument: BlockLinkTileCarouselData,
61
- keepExploringMission: BlockLinkTileCarouselData,
61
+ keepExploringMission: [
62
+ BlockLinkTileCarouselData[0],
63
+ BlockLinkTileCarouselData[1],
64
+ BlockLinkTileCarouselData[2]
65
+ ],
62
66
  keepExploringTarget: BlockLinkTileCarouselData,
63
67
  label: 'Image',
64
68
  piaNumber: 'PIA23356',
@@ -40,7 +40,7 @@
40
40
  />
41
41
  <MixinFancybox
42
42
  v-if="data.image"
43
- :src="data.image.original"
43
+ :src="data.image.original || data.image.src?.url"
44
44
  :caption="data.image.caption"
45
45
  :credit="data.image.credit"
46
46
  :title="data.title"
@@ -31,7 +31,15 @@ export const BaseStory = {
31
31
  slug: 'nasas-ingenuity-mars-helicopter-recharges-its-batteries-in-flight',
32
32
  url: '/news/nasas-ingenuity-mars-helicopter-recharges-its-batteries-in-flight',
33
33
  title: "NASA's Ingenuity Mars Helicopter Recharges Its Batteries in Flight",
34
- firstPublishedAt: '2024-06-20T20:36:49.657301+00:00',
34
+ publicationDate: '2024-06-20 20:36:49.657301+00:00',
35
+ authors: [
36
+ {
37
+ author: {
38
+ name: 'Author Name',
39
+ organization: 'Organization Name'
40
+ }
41
+ }
42
+ ],
35
43
  getTopicsForDisplay: [
36
44
  {
37
45
  title: 'Mars',
@@ -3,29 +3,31 @@ import { computed } from 'vue'
3
3
  import isEmpty from 'lodash/isEmpty.js'
4
4
  import type { StreamfieldBlockData } from './../../../components/BlockStreamfield/BlockStreamfield.vue'
5
5
  import type {
6
+ AuthorObject,
6
7
  ImageObject,
7
8
  PageResponseObject,
8
9
  RelatedLinkObject,
9
10
  Topic,
10
11
  ThumbnailObject
11
12
  } from './../../../interfaces'
12
- import HeroMedia from '@explorer-1/vue/src/components/HeroMedia/HeroMedia.vue'
13
- import LayoutHelper from '@explorer-1/vue/src/components/LayoutHelper/LayoutHelper.vue'
14
- import DetailHeadline from '@explorer-1/vue/src/components/DetailHeadline/DetailHeadline.vue'
15
- import ShareButtonsEdu from '@explorer-1/vue/src/components/ShareButtonsEdu/ShareButtonsEdu.vue'
16
- import BlockImageStandard from '@explorer-1/vue/src/components/BlockImage/BlockImageStandard.vue'
17
- import BlockText from '@explorer-1/vue/src/components/BlockText/BlockText.vue'
18
- import BlockStreamfield from '@explorer-1/vue/src/components/BlockStreamfield/BlockStreamfield.vue'
13
+ import HeroMedia from './../../../components/HeroMedia/HeroMedia.vue'
14
+ import LayoutHelper from './../../../components/LayoutHelper/LayoutHelper.vue'
15
+ import DetailHeadline from './../../../components/DetailHeadline/DetailHeadline.vue'
16
+ import ShareButtonsEdu from './../../../components/ShareButtonsEdu/ShareButtonsEdu.vue'
17
+ import BlockImageStandard from './../../../components/BlockImage/BlockImageStandard.vue'
18
+ import BlockText from './../../../components/BlockText/BlockText.vue'
19
+ import BlockStreamfield from './../../../components/BlockStreamfield/BlockStreamfield.vue'
19
20
 
20
21
  interface PageEduNewsDetailObject extends PageResponseObject {
21
22
  url: string
22
23
  heroImage: ImageObject
24
+ heroImageInline: ImageObject
23
25
  thumbnailImage: ThumbnailObject
24
26
  heroPosition: string
25
27
  heroConstrain: boolean
26
28
  heroImageCaption: string
27
- firstPublishedAt: string
28
- lastPublishedAt: string
29
+ authors: AuthorObject[]
30
+ publicationDate: string
29
31
  title: string
30
32
  getTopicsForDisplay: Topic[]
31
33
  summary: string
@@ -62,7 +64,7 @@ const computedClass = computed(() => {
62
64
  })
63
65
 
64
66
  const dateTimeArray = computed(() => {
65
- return props.data.firstPublishedAt.split('T')
67
+ return props.data.publicationDate.split(' ')
66
68
  })
67
69
  </script>
68
70
  <template>
@@ -97,6 +99,7 @@ const dateTimeArray = computed(() => {
97
99
  >
98
100
  <DetailHeadline
99
101
  :title="data.title"
102
+ :author="data.authors"
100
103
  :publication-date="dateTimeArray?.length ? dateTimeArray[0] : undefined"
101
104
  :publication-time="dateTimeArray?.length ? dateTimeArray[1] : undefined"
102
105
  :topics="data.getTopicsForDisplay"
@@ -118,9 +121,9 @@ const dateTimeArray = computed(() => {
118
121
  class="lg:mb-22 mt-10 mb-10"
119
122
  >
120
123
  <BlockImageStandard
121
- :data="data.heroImage"
122
- :display-caption="data.heroImage.displayCaption"
123
- :caption="data.heroImage.caption"
124
+ :data="data.heroImageInline"
125
+ :display-caption="data.heroImageInline.displayCaption"
126
+ :caption="data.heroImageInline.caption"
124
127
  :constrain="data.heroConstrain"
125
128
  />
126
129
  </LayoutHelper>
@@ -13,7 +13,7 @@
13
13
  <div class="max-w-screen-3xl lg:mb-24 mx-auto mt-10 mb-8">
14
14
  <MixinFancybox
15
15
  v-if="data.image"
16
- :src="data.image.original"
16
+ :src="data.image.original || data.image.src?.url"
17
17
  :caption="data.image.caption"
18
18
  :credit="data.image.credit"
19
19
  :detail-url="data.image.detailUrl"
@@ -1,4 +1,5 @@
1
- import dayjs from './dayjs'
1
+ // must include `.js`
2
+ import dayjs from './dayjs.js'
2
3
 
3
4
  const filters = {
4
5
  // To support more locales update add imports to dayjs.js'
@@ -213,7 +213,11 @@ export const mixinGetExternalLink = (link: RelatedLinkObject): string | undefine
213
213
  // Gets the fully qualified canonical URL of the current page if passed $route.path string
214
214
  export const mixinCanonicalUrl = (path: string): string => {
215
215
  const domain = 'https://www.jpl.nasa.gov'
216
- return domain + path
216
+ if (path.startsWith('http')) {
217
+ return path
218
+ } else {
219
+ return domain + path
220
+ }
217
221
  }
218
222
  // Used to construct an array of image objects to use with BaseLightbox
219
223
  // TODO: currently only assembles an array of 1 item (single image lightbox).