@explorer-1/vue 0.1.8 → 0.2.0

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/explorer-1-vue.js +4409 -4374
  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/DetailHeadline/DetailHeadline.stories.d.ts +13 -1
  6. package/dist/src/components/DetailHeadline/DetailHeadline.vue.d.ts +28 -3
  7. package/dist/src/components/HomepageEmbedBlock/HomepageEmbedBlock.stories.d.ts +1 -0
  8. package/dist/src/templates/PageImageDetail/PageImageDetail.stories.d.ts +27 -2
  9. package/dist/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.stories.d.ts +21 -3
  10. package/dist/src/templates/www/PageAsteroidWatchIndex/PageAsteroidWatchIndex.stories.d.ts +1 -1
  11. package/dist/src/templates/www/PageHomepage/PageHomepage.stories.d.ts +1 -0
  12. package/dist/style.css +1 -1
  13. package/package.json +2 -2
  14. package/src/components/BlockImage/BlockImageFullBleed.vue +1 -1
  15. package/src/components/BlockImage/BlockImageStandard.vue +1 -1
  16. package/src/components/BlockImageCarousel/BlockImageCarousel.stories.js +1 -1
  17. package/src/components/BlockImageCarousel/BlockImageCarousel.vue +1 -1
  18. package/src/components/BlockImageCarouselItem/BlockImageCarouselItem.vue +1 -1
  19. package/src/components/BlockImageGallery/BlockImageGallery.vue +1 -1
  20. package/src/components/BlockInlineImage/BlockInlineImage.vue +41 -39
  21. package/src/components/BlockStreamfield/BlockStreamfield.vue +0 -1
  22. package/src/components/DetailHeadline/DetailHeadline.stories.js +20 -0
  23. package/src/components/DetailHeadline/DetailHeadline.vue +45 -12
  24. package/src/components/NavSecondary/NavSecondary.vue +8 -2
  25. package/src/components/TheFooter/TheFooter.vue +6 -8
  26. package/src/main.ts +1 -1
  27. package/src/templates/PageImageDetail/PageImageDetail.vue +1 -1
  28. package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.stories.js +9 -1
  29. package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.vue +16 -13
  30. package/src/templates/www/PageInfographicDetail/PageInfographicDetail.vue +1 -1
  31. package/src/utils/filters.js +2 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@explorer-1/vue",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -28,7 +28,7 @@
28
28
  "vue": "^3.4.21",
29
29
  "vue-observe-visibility": "^1.0.0",
30
30
  "vue3-compare-image": "^1.2.5",
31
- "@explorer-1/common": "1.0.5"
31
+ "@explorer-1/common": "1.1.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@vitejs/plugin-vue": "^5.0.4",
@@ -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>
@@ -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
  })
@@ -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;
@@ -184,8 +184,14 @@ export default defineComponent({
184
184
  }
185
185
  }
186
186
  @screen lg {
187
- @apply top-28 edu:top-18;
187
+ @apply top-28;
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>
@@ -32,7 +32,7 @@
32
32
  <div class="footer-extras lg:col-span-3 col-span-12">
33
33
  <!-- email sign up -->
34
34
  <div class="text-subtitle text-blue edu:text-white lg:mb-5 mb-3">
35
- Get the Latest from JPL
35
+ {{ `Get the Latest from JPL ${themeStore.isEdu ? 'Education' : ''} ` }}
36
36
  </div>
37
37
  <TheFooterSignUp class="lg:mb-10 mb-8" />
38
38
  <!-- social media -->
@@ -101,9 +101,7 @@
101
101
  <div class="3xl:px-0 container px-4 mx-auto">
102
102
  <div v-if="data && data.relatedNasaSites">
103
103
  <div class="text-subtitle text-blue edu:text-white mb-5">
104
- <template v-if="themeStore.theme === 'ThemeEdu'">
105
- Related NASA Education Sites
106
- </template>
104
+ <template v-if="themeStore.isEdu"> Related NASA Education Sites </template>
107
105
  <template v-else> Related NASA Sites </template>
108
106
  </div>
109
107
  <div class="auto-col-4">
@@ -148,9 +146,9 @@
148
146
  >
149
147
  <div
150
148
  v-if="commitSha"
151
- class="lg:inline-block lg:mb-0 block px-3 mb-2"
149
+ class="lg:inline-block lg:mb-0 block pr-4 mb-2"
152
150
  >
153
- <span class="text-gray-light font-bold">Version:</span>
151
+ <span class="text-gray-light font-bold inline-block pr-1">Version:</span>
154
152
  <span>{{ commitSha }}</span>
155
153
  </div>
156
154
  <div
@@ -159,7 +157,7 @@
159
157
  class="lg:inline-block lg:mb-0 block mb-2"
160
158
  :class="{ 'ml-5': index !== 0 }"
161
159
  >
162
- <span class="font-bold">{{ item.label }}:</span>
160
+ <span class="font-bold inline-block pr-1">{{ item.label }}:</span>
163
161
  <span>{{ item.text }}</span>
164
162
  </div>
165
163
  </div>
@@ -168,7 +166,7 @@
168
166
  v-if="commitSha != null"
169
167
  class="lg:inline-block lg:mb-0 block px-3 mb-2"
170
168
  >
171
- <span class="text-gray-light font-bold">Version:</span>
169
+ <span class="text-gray-light font-bold inline-block pr-1">Version:</span>
172
170
  <span>{{ commitSha }}</span>
173
171
  </div>
174
172
  </div>
package/src/main.ts CHANGED
@@ -6,7 +6,7 @@ import filters from './utils/filters'
6
6
  // @ts-ignore
7
7
  import vClickOutside from 'click-outside-vue3'
8
8
  import VueCompareImage from 'vue3-compare-image'
9
- import './assets/scss/styles.scss'
9
+ import './assets/scss/styles-with-fonts.scss'
10
10
  import App from './App.vue'
11
11
 
12
12
  const pinia = createPinia()
@@ -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'