@explorer-1/vue 0.2.3 → 0.2.5
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/components.d.ts +6 -3
- package/dist/explorer-1-vue.js +5603 -5375
- package/dist/explorer-1-vue.umd.cjs +12 -12
- package/dist/src/components/BlockCardGrid/BlockCardGrid.stories.d.ts +60 -0
- package/dist/src/components/BlockCardGrid/BlockCardGrid.vue.d.ts +33 -0
- package/dist/src/components/{BlockCard/BlockCard.stories.d.ts → BlockCardGridItem/BlockCardGridItem.stories.d.ts} +18 -4
- package/dist/src/components/{BlockCardGroup/BlockCardGroup.vue.d.ts → BlockCardGridItem/BlockCardGridItem.vue.d.ts} +10 -12
- package/dist/src/components/{BlockCard/BlockCard.vue.d.ts → BlockCardGridItem/BlockCardGridItemElement.vue.d.ts} +20 -14
- package/dist/src/components/BlockCircleImageCard/BlockCircleImageCard.stories.d.ts +1 -0
- package/dist/src/components/BlockHeading/BlockHeading.vue.d.ts +25 -2
- package/dist/src/components/BlockLinkCard/BlockLinkCard.stories.d.ts +1 -0
- package/dist/src/components/BlockLinkTile/BlockLinkTile.stories.d.ts +1 -0
- package/dist/src/components/BlockListCards/BlockListCards.stories.d.ts +1 -0
- package/dist/src/components/BlockStreamfield/BlockStreamfield.stories.d.ts +60 -0
- package/dist/src/components/BlockStreamfield/BlockStreamfield.vue.d.ts +2 -3
- package/dist/src/components/DetailHeadline/DetailHeadline.stories.d.ts +30 -1
- package/dist/src/components/DetailHeadline/DetailHeadline.vue.d.ts +37 -0
- package/dist/src/components/LayoutHelper/LayoutHelper.vue.d.ts +9 -0
- package/dist/src/components/NavDesktop/NavDesktop.stories.d.ts +3 -0
- package/dist/src/components/NavDesktop/NavDesktop.vue.d.ts +1 -0
- package/dist/src/components/NavDesktop/NavDesktopDropdown.vue.d.ts +1 -0
- package/dist/src/components/NavDesktopEdu/NavDesktopEdu.stories.d.ts +1 -0
- package/dist/src/components/NavDropdownToggle/NavDropdownToggle.vue.d.ts +19 -6
- package/dist/src/components/NavJumpMenu/NavJumpMenu.stories.d.ts +31 -0
- package/dist/src/components/NavMobile/NavMobile.stories.d.ts +30 -3
- package/dist/src/components/NavMobile/NavMobile.vue.d.ts +1 -0
- package/dist/src/components/NavMobile/NavMobileDropdown.vue.d.ts +9 -1
- package/dist/src/components/NavMobile/NavMobileEdu.stories.d.ts +3 -0
- package/dist/src/components/NavMobile/NavMobileSecondaryDropdown.vue.d.ts +7 -0
- package/dist/src/components/NavSecondary/NavSecondary.stories.d.ts +8 -0
- package/dist/src/components/NavSecondary/NavSecondary.vue.d.ts +23 -1
- package/dist/src/components/NavSecondary/NavSecondaryDropdown.vue.d.ts +33 -2
- package/dist/src/components/NavSecondary/NavSecondaryDropdownContent.vue.d.ts +11 -1
- package/dist/src/components/NavSecondary/NavSecondaryLink.vue.d.ts +21 -3
- package/dist/src/components/ThumbnailCarousel/ThumbnailCarousel.stories.d.ts +1 -0
- package/dist/src/docs/foundation/grid_layouthelpers.stories.d.ts +36 -0
- package/dist/src/interfaces.d.ts +13 -3
- package/dist/src/store/header.d.ts +2 -0
- package/dist/src/templates/PageNewsDetail/PageNewsDetail.stories.d.ts +8 -0
- package/dist/src/templates/edu/{PageEduResourceArticle/PageEduResourceArticle.stories.d.ts → PageEduExplainerArticle/PageEduExplainerArticle.stories.d.ts} +4 -2
- package/dist/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.stories.d.ts +1007 -6
- package/dist/src/templates/www/PageAsteroidWatchIndex/PageAsteroidWatchIndex.stories.d.ts +60 -0
- package/dist/src/templates/www/PageRoboticsDetail/PageRoboticsDetail.stories.d.ts +29 -2
- package/dist/src/utils/eventBus.d.ts +1 -0
- package/dist/src/utils/getHeadingId.d.ts +1 -0
- package/dist/src/utils/mixins.d.ts +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -2
- package/src/components/BaseAudio/BaseAudio.vue +3 -4
- package/src/components/BaseLink/BaseLink.vue +2 -0
- package/src/components/BaseTag/BaseTag.vue +4 -4
- package/src/components/BlockHeading/BlockHeading.vue +28 -0
- package/src/components/BlockStreamfield/BlockStreamfield.vue +5 -1
- package/src/components/DetailHeadline/DetailHeadline.stories.js +28 -2
- package/src/components/DetailHeadline/DetailHeadline.vue +85 -32
- package/src/components/NavDesktop/NavDesktopDropdown.vue +2 -4
- package/src/components/NavDropdownToggle/NavDropdownToggle.vue +8 -3
- package/src/components/NavJumpMenu/NavJumpMenu.stories.js +47 -0
- package/src/components/NavJumpMenu/NavJumpMenu.vue +141 -0
- package/src/components/NavJumpMenu/NavJumpMenuContent.vue +74 -0
- package/src/components/NavMobile/NavMobile.vue +2 -4
- package/src/components/NavMobile/NavMobileDropdown.vue +8 -4
- package/src/components/NavMobile/NavMobileSecondaryDropdown.vue +4 -1
- package/src/components/NavSecondary/NavSecondary.stories.js +8 -3
- package/src/components/NavSecondary/NavSecondary.vue +26 -6
- package/src/components/NavSecondary/NavSecondaryDropdown.vue +52 -17
- package/src/components/NavSecondary/NavSecondaryDropdownContent.vue +5 -1
- package/src/components/NavSecondary/NavSecondaryLink.vue +38 -11
- package/src/interfaces.ts +7 -1
- package/src/store/header.ts +6 -1
- package/src/templates/PageNewsDetail/PageNewsDetail.stories.js +1 -0
- package/src/templates/PageNewsDetail/PageNewsDetail.vue +1 -0
- package/src/templates/edu/PageEduEventDetail/PageEduEventDetail.vue +2 -2
- package/src/templates/edu/{PageEduResourceArticle/PageEduResourceArticle.stories.js → PageEduExplainerArticle/PageEduExplainerArticle.stories.js} +8 -6
- package/src/templates/edu/{PageEduResourceArticle/PageEduResourceArticle.vue → PageEduExplainerArticle/PageEduExplainerArticle.vue} +5 -2
- package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.stories.js +7 -4
- package/src/templates/edu/PageEduNewsDetail/PageEduNewsDetail.vue +18 -2
- package/src/utils/eventBus.ts +3 -0
- package/src/utils/getHeadingId.ts +5 -0
- package/src/utils/mixins.ts +5 -1
- package/dist/src/components/BlockCardGroup/BlockCardGroup.stories.d.ts +0 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explorer-1/vue",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"dayjs": "^1.11.11",
|
|
22
22
|
"fast-qs": "^2.0.3",
|
|
23
23
|
"lodash": "^4.17.21",
|
|
24
|
+
"mitt": "^3.0.1",
|
|
24
25
|
"sass": "^1.77.4",
|
|
25
26
|
"swiper": "^11.1.3",
|
|
26
27
|
"tailwindcss": "^3.4.3",
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
"vue": "^3.4.21",
|
|
29
30
|
"vue-observe-visibility": "^1.0.0",
|
|
30
31
|
"vue3-compare-image": "^1.2.5",
|
|
31
|
-
"@explorer-1/common": "1.1.
|
|
32
|
+
"@explorer-1/common": "1.1.1"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
@@ -119,6 +119,7 @@
|
|
|
119
119
|
</template>
|
|
120
120
|
<script lang="ts">
|
|
121
121
|
import { defineComponent } from 'vue'
|
|
122
|
+
// import { eventBus } from './../../utils/eventBus'
|
|
122
123
|
import IconPlay from './../Icons/IconPlay.vue'
|
|
123
124
|
import IconPause from './../Icons/IconPause.vue'
|
|
124
125
|
import IconVolume from './../Icons/IconVolume.vue'
|
|
@@ -326,10 +327,8 @@ export default defineComponent({
|
|
|
326
327
|
this.audio.addEventListener('play', this._handlePlayPause)
|
|
327
328
|
this.audio.addEventListener('ended', this._handleEnded)
|
|
328
329
|
}
|
|
329
|
-
// TODO: VUE3:
|
|
330
|
-
//
|
|
331
|
-
// scoped slots? https://github.com/vuejs/vue/issues/4332
|
|
332
|
-
// this.$root?.$on('play', this.pauseOthers)
|
|
330
|
+
// TODO: VUE3: pass uuID to pauseOthers() method
|
|
331
|
+
// eventBus.on('play', () => this.pauseOthers())
|
|
333
332
|
},
|
|
334
333
|
getAudio() {
|
|
335
334
|
return this.$el.querySelectorAll('audio')[0]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { defineComponent } from 'vue'
|
|
3
|
+
import { eventBus } from './../../utils/eventBus'
|
|
3
4
|
import MixinAnimationCaret from './../MixinAnimationCaret/MixinAnimationCaret.vue'
|
|
4
5
|
|
|
5
6
|
interface Variants {
|
|
@@ -145,6 +146,7 @@ export default defineComponent({
|
|
|
145
146
|
clickEvent() {
|
|
146
147
|
this.$root?.$emit('linkClicked')
|
|
147
148
|
this.$emit('specificLinkClicked')
|
|
149
|
+
eventBus.emit('linkClicked')
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
})
|
|
@@ -9,9 +9,9 @@ const variantMap: Attributes = {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const sizeMap: Attributes = {
|
|
12
|
-
sm: 'text-xs
|
|
13
|
-
md: 'text-base
|
|
14
|
-
lg: 'text-lg
|
|
12
|
+
sm: 'text-xs border-t-2 py-1 px-2.5',
|
|
13
|
+
md: 'text-xs lg:text-base border-t py-1.5 px-3.5',
|
|
14
|
+
lg: 'text-base lg:text-lg border-t py-1.5 px-5'
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
interface BaseTagProps {
|
|
@@ -28,7 +28,7 @@ const props = withDefaults(defineProps<BaseTagProps>(), {
|
|
|
28
28
|
<template>
|
|
29
29
|
<p
|
|
30
30
|
:class="`${variantMap[props.variant]} ${sizeMap[props.size]}`"
|
|
31
|
-
class="ThemeVariantLight text-contrast-none inline-block text-white font-bold edu:font-extrabold rounded-full leading-tight m-0"
|
|
31
|
+
class="ThemeVariantLight text-contrast-none inline-block text-white font-bold edu:font-extrabold rounded-full leading-tight m-0 uppercase"
|
|
32
32
|
>
|
|
33
33
|
<slot />
|
|
34
34
|
<span class="sr-only">.</span>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<BaseHeading
|
|
3
3
|
v-if="data"
|
|
4
|
+
:id="getId"
|
|
4
5
|
:level="data.level"
|
|
6
|
+
class="BlockHeading"
|
|
7
|
+
:class="{ 'has-anchor': generateId }"
|
|
5
8
|
>
|
|
6
9
|
{{ data.heading }}
|
|
7
10
|
</BaseHeading>
|
|
@@ -9,6 +12,7 @@
|
|
|
9
12
|
|
|
10
13
|
<script lang="ts">
|
|
11
14
|
import { defineComponent } from 'vue'
|
|
15
|
+
import { getHeadingId } from '../../utils/getHeadingId'
|
|
12
16
|
import BaseHeading from './../BaseHeading/BaseHeading.vue'
|
|
13
17
|
|
|
14
18
|
export default defineComponent({
|
|
@@ -20,7 +24,31 @@ export default defineComponent({
|
|
|
20
24
|
data: {
|
|
21
25
|
type: Object,
|
|
22
26
|
required: false
|
|
27
|
+
},
|
|
28
|
+
index: {
|
|
29
|
+
type: Number,
|
|
30
|
+
required: false,
|
|
31
|
+
default: undefined
|
|
32
|
+
},
|
|
33
|
+
generateId: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
computed: {
|
|
39
|
+
getId() {
|
|
40
|
+
return this.generateId ? getHeadingId(this.data?.heading, this.index) : undefined
|
|
23
41
|
}
|
|
24
42
|
}
|
|
25
43
|
})
|
|
26
44
|
</script>
|
|
45
|
+
<style lang="scss">
|
|
46
|
+
.BlockHeading {
|
|
47
|
+
&:target {
|
|
48
|
+
@apply scroll-mt-14;
|
|
49
|
+
@screen lg {
|
|
50
|
+
@apply scroll-mt-20;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
indent="col-3"
|
|
12
12
|
class="mb-5"
|
|
13
13
|
>
|
|
14
|
-
<BlockHeading
|
|
14
|
+
<BlockHeading
|
|
15
|
+
:data="block"
|
|
16
|
+
:index="index"
|
|
17
|
+
generate-id
|
|
18
|
+
/>
|
|
15
19
|
</LayoutHelper>
|
|
16
20
|
|
|
17
21
|
<!-- custom margin bottom that matches BlockText styles if followed by InlineImageBlock -->
|
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
import DetailHeadline from './DetailHeadline.vue'
|
|
1
|
+
import DetailHeadline, { pillColorVariants } from './DetailHeadline.vue'
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
title: 'Components/Utilities/DetailHeadline',
|
|
5
5
|
component: DetailHeadline,
|
|
6
|
-
excludeStories: /.*Data
|
|
6
|
+
excludeStories: /.*Data$/,
|
|
7
|
+
argTypes: {
|
|
8
|
+
ariaLabel: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
description:
|
|
11
|
+
"ARIA label. Recommended if your button label isn't descriptive, or if it only contains an icon."
|
|
12
|
+
},
|
|
13
|
+
pillColor: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Color of pill',
|
|
16
|
+
control: {
|
|
17
|
+
type: 'select'
|
|
18
|
+
},
|
|
19
|
+
options: pillColorVariants,
|
|
20
|
+
table: {
|
|
21
|
+
defaultValue: { summary: 'primary' }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
7
25
|
}
|
|
8
26
|
|
|
9
27
|
export const DetailHeadlineData = {
|
|
10
28
|
title: "NASA's Ingenuity Mars Helicopter Recharges Its Batteries in Flight",
|
|
11
29
|
publicationDate: '2020-08-13',
|
|
30
|
+
readTime: '3 min read',
|
|
12
31
|
author: {
|
|
13
32
|
name: 'Jane Platt',
|
|
14
33
|
organization: 'JPL'
|
|
@@ -66,3 +85,10 @@ export const NoAuthor = {
|
|
|
66
85
|
]
|
|
67
86
|
}
|
|
68
87
|
}
|
|
88
|
+
|
|
89
|
+
export const Pill = {
|
|
90
|
+
args: {
|
|
91
|
+
...DetailHeadlineData,
|
|
92
|
+
pill: true
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -1,43 +1,63 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="
|
|
2
|
+
<div v-if="hasData">
|
|
3
3
|
<div
|
|
4
|
-
v-if="
|
|
5
|
-
class="flex flex-wrap items-
|
|
4
|
+
v-if="hasEyebrow"
|
|
5
|
+
class="flex flex-wrap items-center mb-3"
|
|
6
6
|
>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
<template v-if="pill && pillLabel">
|
|
8
|
+
<BaseTag
|
|
9
|
+
:variant="pillColor"
|
|
10
|
+
size="lg"
|
|
11
|
+
class="mr-3"
|
|
12
|
+
>
|
|
13
|
+
{{ pillLabel }}
|
|
14
|
+
</BaseTag>
|
|
15
|
+
</template>
|
|
16
|
+
<template v-else>
|
|
17
|
+
<div
|
|
18
|
+
v-if="topics && topics.length"
|
|
19
|
+
class="inline"
|
|
16
20
|
>
|
|
17
|
-
<span :itemprop="schema ? 'articleSection' : undefined">
|
|
18
|
-
{{ topics[0].title }}
|
|
19
|
-
</span>
|
|
20
|
-
</BaseLink>
|
|
21
|
-
</div>
|
|
22
|
-
<span
|
|
23
|
-
v-else-if="label"
|
|
24
|
-
class="text-subtitle py-3 edu:text-primary"
|
|
25
|
-
>
|
|
26
|
-
<template v-if="!labelLink">
|
|
27
|
-
{{ label }}
|
|
28
|
-
</template>
|
|
29
|
-
<template v-else>
|
|
30
21
|
<BaseLink
|
|
31
22
|
variant="secondary"
|
|
32
|
-
:to="
|
|
23
|
+
:to="topics[0].url"
|
|
33
24
|
class="py-3"
|
|
34
25
|
:use-primary-color="themeStore.theme === 'ThemeEdu'"
|
|
35
26
|
>
|
|
36
|
-
|
|
27
|
+
<span :itemprop="schema ? 'articleSection' : undefined">
|
|
28
|
+
{{ topics[0].title }}
|
|
29
|
+
</span>
|
|
37
30
|
</BaseLink>
|
|
38
|
-
</
|
|
31
|
+
</div>
|
|
32
|
+
<span
|
|
33
|
+
v-else-if="label"
|
|
34
|
+
class="text-subtitle py-3 edu:text-primary"
|
|
35
|
+
>
|
|
36
|
+
<template v-if="!labelLink">
|
|
37
|
+
{{ label }}
|
|
38
|
+
</template>
|
|
39
|
+
<template v-else>
|
|
40
|
+
<BaseLink
|
|
41
|
+
variant="secondary"
|
|
42
|
+
:to="labelLink"
|
|
43
|
+
class="py-3"
|
|
44
|
+
:use-primary-color="themeStore.theme === 'ThemeEdu'"
|
|
45
|
+
>
|
|
46
|
+
{{ label }}
|
|
47
|
+
</BaseLink>
|
|
48
|
+
</template>
|
|
49
|
+
</span>
|
|
50
|
+
</template>
|
|
51
|
+
<span
|
|
52
|
+
v-if="hasTag"
|
|
53
|
+
class="sr-only"
|
|
54
|
+
>.</span
|
|
55
|
+
>
|
|
56
|
+
<span
|
|
57
|
+
:class="`${hasTag && !pill ? 'divide-gray-mid-dark border-l ml-3 pl-3 ' : ''} my-4 text-gray-mid-dark uppercase text-sm lg:text-base leading-none`"
|
|
58
|
+
>
|
|
59
|
+
{{ readTime }}
|
|
39
60
|
</span>
|
|
40
|
-
<span class="sr-only">.</span>
|
|
41
61
|
</div>
|
|
42
62
|
<BaseHeading
|
|
43
63
|
level="h1"
|
|
@@ -46,8 +66,8 @@
|
|
|
46
66
|
>{{ title }}
|
|
47
67
|
</BaseHeading>
|
|
48
68
|
<div
|
|
49
|
-
v-if="
|
|
50
|
-
class="lg:text-base text-gray-mid-dark divide-gray-mid-dark px-3 mt-5 -ml-3 text-sm leading-
|
|
69
|
+
v-if="hasByline"
|
|
70
|
+
class="lg:text-base text-gray-mid-dark divide-gray-mid-dark px-3 mt-5 -ml-3 text-sm leading-none"
|
|
51
71
|
>
|
|
52
72
|
<span
|
|
53
73
|
v-if="authors?.length"
|
|
@@ -102,12 +122,16 @@ import { useThemeStore } from '../../store/theme'
|
|
|
102
122
|
import type { Topic, AuthorObject } from './../../interfaces'
|
|
103
123
|
import BaseLink from './../BaseLink/BaseLink.vue'
|
|
104
124
|
import BaseHeading from './../BaseHeading/BaseHeading.vue'
|
|
125
|
+
import BaseTag from '../BaseTag/BaseTag.vue'
|
|
126
|
+
|
|
127
|
+
export const pillColorVariants = ['primary', 'secondary', 'action']
|
|
105
128
|
|
|
106
129
|
export default defineComponent({
|
|
107
130
|
name: 'DetailHeadline',
|
|
108
131
|
components: {
|
|
109
132
|
BaseLink,
|
|
110
|
-
BaseHeading
|
|
133
|
+
BaseHeading,
|
|
134
|
+
BaseTag
|
|
111
135
|
},
|
|
112
136
|
props: {
|
|
113
137
|
title: {
|
|
@@ -130,6 +154,11 @@ export default defineComponent({
|
|
|
130
154
|
required: false,
|
|
131
155
|
default: undefined
|
|
132
156
|
},
|
|
157
|
+
readTime: {
|
|
158
|
+
type: String,
|
|
159
|
+
required: false,
|
|
160
|
+
default: undefined
|
|
161
|
+
},
|
|
133
162
|
topics: {
|
|
134
163
|
type: Array as PropType<Topic[]>,
|
|
135
164
|
required: false,
|
|
@@ -146,6 +175,15 @@ export default defineComponent({
|
|
|
146
175
|
required: false,
|
|
147
176
|
default: undefined
|
|
148
177
|
},
|
|
178
|
+
pill: {
|
|
179
|
+
type: Boolean,
|
|
180
|
+
default: false
|
|
181
|
+
},
|
|
182
|
+
pillColor: {
|
|
183
|
+
type: String,
|
|
184
|
+
default: 'primary',
|
|
185
|
+
validator: (prop: string): boolean => pillColorVariants.includes(prop)
|
|
186
|
+
},
|
|
149
187
|
schema: {
|
|
150
188
|
type: Boolean,
|
|
151
189
|
default: false
|
|
@@ -153,6 +191,18 @@ export default defineComponent({
|
|
|
153
191
|
},
|
|
154
192
|
computed: {
|
|
155
193
|
...mapStores(useThemeStore),
|
|
194
|
+
hasTag(): boolean {
|
|
195
|
+
return this.topics?.length || this.label ? true : false
|
|
196
|
+
},
|
|
197
|
+
hasEyebrow(): boolean {
|
|
198
|
+
return this.hasTag || this.readTime ? true : false
|
|
199
|
+
},
|
|
200
|
+
hasByline(): boolean {
|
|
201
|
+
return this.authors?.length || this.publicationDate ? true : false
|
|
202
|
+
},
|
|
203
|
+
hasData(): boolean {
|
|
204
|
+
return this.title || this.hasEyebrow || this.hasByline ? true : false
|
|
205
|
+
},
|
|
156
206
|
pubDatetime(): string | undefined {
|
|
157
207
|
const currentTime = this.publicationTime || '00:00:00'
|
|
158
208
|
const returnDate = new Date(this.publicationDate + ' ' + currentTime)
|
|
@@ -171,6 +221,9 @@ export default defineComponent({
|
|
|
171
221
|
authors = [this.author] as AuthorObject[]
|
|
172
222
|
}
|
|
173
223
|
return authors
|
|
224
|
+
},
|
|
225
|
+
pillLabel(): string | undefined {
|
|
226
|
+
return this.label ? this.label : this.topics?.length ? this.topics[0].title : undefined
|
|
174
227
|
}
|
|
175
228
|
}
|
|
176
229
|
})
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
|
|
38
38
|
<script lang="ts">
|
|
39
39
|
import { defineComponent } from 'vue'
|
|
40
|
+
import { eventBus } from './../../utils/eventBus'
|
|
40
41
|
import { mapStores } from 'pinia'
|
|
41
42
|
import { useHeaderStore } from './../../store/header'
|
|
42
43
|
import NavDropdownToggle from './../NavDropdownToggle/NavDropdownToggle.vue'
|
|
@@ -80,10 +81,7 @@ export default defineComponent({
|
|
|
80
81
|
}
|
|
81
82
|
},
|
|
82
83
|
mounted() {
|
|
83
|
-
|
|
84
|
-
// TODO: find a cleaner way to do this w/o using mounted or root level events
|
|
85
|
-
// scoped slots? https://github.com/vuejs/vue/issues/4332
|
|
86
|
-
// this.$root?.$on('linkClicked', this.closeDropdown)
|
|
84
|
+
eventBus.on('linkClicked', () => this.closeDropdown())
|
|
87
85
|
},
|
|
88
86
|
methods: {
|
|
89
87
|
toggleDropdown() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<button
|
|
3
3
|
class="NavDropdownToggle group cursor-pointer"
|
|
4
|
-
:class="{ '-active': isActivePath }"
|
|
4
|
+
:class="{ '-active': isActivePath, '-invert': invert }"
|
|
5
5
|
:aria-expanded="ariaExpanded"
|
|
6
6
|
@click="clickEvent()"
|
|
7
7
|
@keydown.esc="escEvent()"
|
|
@@ -26,13 +26,18 @@ export default defineComponent({
|
|
|
26
26
|
props: {
|
|
27
27
|
path: {
|
|
28
28
|
type: String,
|
|
29
|
-
|
|
29
|
+
default: undefined
|
|
30
30
|
},
|
|
31
31
|
ariaExpanded: {
|
|
32
32
|
type: Boolean,
|
|
33
|
-
|
|
33
|
+
default: false
|
|
34
|
+
},
|
|
35
|
+
invert: {
|
|
36
|
+
type: Boolean,
|
|
37
|
+
default: false
|
|
34
38
|
}
|
|
35
39
|
},
|
|
40
|
+
emits: ['closeDropdown', 'toggleClicked'],
|
|
36
41
|
computed: {
|
|
37
42
|
isActivePath() {
|
|
38
43
|
if (this.path) {
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import NavJumpMenu from './NavJumpMenu.vue'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Navigation/Jump Menu',
|
|
5
|
+
component: NavJumpMenu,
|
|
6
|
+
tags: ['!autodocs'],
|
|
7
|
+
excludeStories: /.*Data$/
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const JumpLinksData = [
|
|
11
|
+
{
|
|
12
|
+
title: 'Heading title',
|
|
13
|
+
path: '#heading_title'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
title: 'Heading title',
|
|
17
|
+
path: '#heading_title'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
title: 'Heading title',
|
|
21
|
+
path: '#heading_title'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
title: 'Heading title',
|
|
25
|
+
path: '#heading_title'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: 'Heading title',
|
|
29
|
+
path: '#heading_title'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
export const BaseStory = {
|
|
33
|
+
name: 'Jump Menu',
|
|
34
|
+
args: {
|
|
35
|
+
title: 'Page Title',
|
|
36
|
+
jumpLinks: JumpLinksData,
|
|
37
|
+
invert: true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const Light = {
|
|
42
|
+
args: {
|
|
43
|
+
title: 'Page Title',
|
|
44
|
+
jumpLinks: JumpLinksData,
|
|
45
|
+
invert: false
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NavSecondary
|
|
3
|
+
v-if="enabled"
|
|
4
|
+
id="JumpMenuTop"
|
|
5
|
+
ref="NavJumpMenuRef"
|
|
6
|
+
class="NavJumpMenu -hide-until-threshold"
|
|
7
|
+
:invert="invert"
|
|
8
|
+
>
|
|
9
|
+
<template v-for="(item, index) in theBreadcrumbs">
|
|
10
|
+
<template v-if="item.children && item.children.length > 0">
|
|
11
|
+
<NavSecondaryDropdown
|
|
12
|
+
:key="index"
|
|
13
|
+
:item="item"
|
|
14
|
+
:index="index"
|
|
15
|
+
:is-last="theBreadcrumbs && index === theBreadcrumbs.length - 1"
|
|
16
|
+
:invert="invert"
|
|
17
|
+
>
|
|
18
|
+
<NavJumpMenuContent
|
|
19
|
+
:key="index"
|
|
20
|
+
:item="item"
|
|
21
|
+
/>
|
|
22
|
+
</NavSecondaryDropdown>
|
|
23
|
+
</template>
|
|
24
|
+
<template v-else>
|
|
25
|
+
<NavSecondaryLink
|
|
26
|
+
:key="index"
|
|
27
|
+
:item="item"
|
|
28
|
+
:index="index"
|
|
29
|
+
:invert="invert"
|
|
30
|
+
/>
|
|
31
|
+
</template>
|
|
32
|
+
</template>
|
|
33
|
+
</NavSecondary>
|
|
34
|
+
</template>
|
|
35
|
+
<script setup lang="ts">
|
|
36
|
+
import { computed, defineExpose, ref, onMounted, watch } from 'vue'
|
|
37
|
+
import { mixinUpdateSecondary } from './../../utils/mixins'
|
|
38
|
+
import { useRoute } from 'vue-router'
|
|
39
|
+
import NavSecondary from './../NavSecondary/NavSecondary.vue'
|
|
40
|
+
import NavSecondaryDropdown from './../NavSecondary/NavSecondaryDropdown.vue'
|
|
41
|
+
import NavSecondaryLink from './../NavSecondary/NavSecondaryLink.vue'
|
|
42
|
+
import NavJumpMenuContent from './../NavJumpMenu/NavJumpMenuContent.vue'
|
|
43
|
+
import type { BlockData, BreadcrumbPathObject } from './../../interfaces'
|
|
44
|
+
import { getHeadingId } from '../../utils/getHeadingId'
|
|
45
|
+
|
|
46
|
+
interface NavJumpMenuProps {
|
|
47
|
+
title?: string
|
|
48
|
+
jumpLinks?: BreadcrumbPathObject[]
|
|
49
|
+
blocks?: BlockData[]
|
|
50
|
+
headingLevel?: string
|
|
51
|
+
invert?: boolean
|
|
52
|
+
enabled?: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const props = withDefaults(defineProps<NavJumpMenuProps>(), {
|
|
56
|
+
title: undefined,
|
|
57
|
+
jumpLinks: undefined,
|
|
58
|
+
blocks: undefined,
|
|
59
|
+
headingLevel: 'h2',
|
|
60
|
+
enabled: true,
|
|
61
|
+
invert: true,
|
|
62
|
+
hidden: false
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const NavJumpMenuRef = ref()
|
|
66
|
+
|
|
67
|
+
const theJumpLinks = computed(() => {
|
|
68
|
+
if (props.jumpLinks) {
|
|
69
|
+
return props.jumpLinks
|
|
70
|
+
} else if (props.blocks) {
|
|
71
|
+
const indexedBlocks = props.blocks.map((b, index) => {
|
|
72
|
+
return {
|
|
73
|
+
...b,
|
|
74
|
+
index: index
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
const filteredBlocks = indexedBlocks.filter((b) => {
|
|
78
|
+
return b.blockType === 'HeadingBlock' && b.level === props.headingLevel
|
|
79
|
+
})
|
|
80
|
+
// map to the correct data shape
|
|
81
|
+
const links: BreadcrumbPathObject[] = filteredBlocks.map((l) => {
|
|
82
|
+
return {
|
|
83
|
+
// @ts-expect-error using parameter that was added to BlockData
|
|
84
|
+
path: '#' + getHeadingId(l.heading, l.index),
|
|
85
|
+
title: l.heading
|
|
86
|
+
} as BreadcrumbPathObject
|
|
87
|
+
})
|
|
88
|
+
return links
|
|
89
|
+
}
|
|
90
|
+
return []
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const theBreadcrumbs = computed(() => {
|
|
94
|
+
let breadcrumb = undefined
|
|
95
|
+
const rootItem = props.title
|
|
96
|
+
? {
|
|
97
|
+
title: props.title,
|
|
98
|
+
path: '#JumpMenuTop'
|
|
99
|
+
}
|
|
100
|
+
: {
|
|
101
|
+
title: 'Back to top',
|
|
102
|
+
path: '#JumpMenuTop'
|
|
103
|
+
}
|
|
104
|
+
const jumpMenu: BreadcrumbPathObject = {
|
|
105
|
+
title: 'Jump to…',
|
|
106
|
+
path: '#',
|
|
107
|
+
children: theJumpLinks.value as BreadcrumbPathObject[]
|
|
108
|
+
}
|
|
109
|
+
if (theJumpLinks.value) {
|
|
110
|
+
breadcrumb = [rootItem, jumpMenu]
|
|
111
|
+
}
|
|
112
|
+
return breadcrumb as BreadcrumbPathObject[] | undefined
|
|
113
|
+
})
|
|
114
|
+
defineExpose({
|
|
115
|
+
NavJumpMenuRef
|
|
116
|
+
})
|
|
117
|
+
onMounted(() => {
|
|
118
|
+
mixinUpdateSecondary(theBreadcrumbs.value, true)
|
|
119
|
+
})
|
|
120
|
+
const route = useRoute()
|
|
121
|
+
|
|
122
|
+
// repopulate the store with the jump links since the store is cleared on route changes
|
|
123
|
+
watch(
|
|
124
|
+
route,
|
|
125
|
+
() => {
|
|
126
|
+
mixinUpdateSecondary(theBreadcrumbs.value, true)
|
|
127
|
+
}
|
|
128
|
+
// { flush: 'pre', immediate: true, deep: true }
|
|
129
|
+
)
|
|
130
|
+
</script>
|
|
131
|
+
<style lang="scss">
|
|
132
|
+
.NavJumpMenu {
|
|
133
|
+
&.-hide-until-threshold {
|
|
134
|
+
@apply opacity-0 h-0 transition-none overflow-visible;
|
|
135
|
+
&.-is-sticky,
|
|
136
|
+
&.-is-sticky-offset {
|
|
137
|
+
@apply opacity-100 transition-opacity;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ul class="NavJumpMenuContent bg-white">
|
|
3
|
+
<li
|
|
4
|
+
v-for="(child, index) in item.children"
|
|
5
|
+
:key="index"
|
|
6
|
+
class="text-base border-b border-gray-light"
|
|
7
|
+
>
|
|
8
|
+
<BaseLink
|
|
9
|
+
:href="child.path"
|
|
10
|
+
variant="none"
|
|
11
|
+
:link-class="linkClass(child)"
|
|
12
|
+
>
|
|
13
|
+
<span>
|
|
14
|
+
{{ child.title }}
|
|
15
|
+
</span>
|
|
16
|
+
</BaseLink>
|
|
17
|
+
</li>
|
|
18
|
+
</ul>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
import { defineComponent } from 'vue'
|
|
23
|
+
import BaseLink from './../BaseLink/BaseLink.vue'
|
|
24
|
+
|
|
25
|
+
interface NavItemObject {
|
|
26
|
+
path: String
|
|
27
|
+
title: String
|
|
28
|
+
children: [Object]
|
|
29
|
+
}
|
|
30
|
+
export default defineComponent({
|
|
31
|
+
name: 'NavJumpMenuContent',
|
|
32
|
+
components: {
|
|
33
|
+
BaseLink
|
|
34
|
+
},
|
|
35
|
+
props: {
|
|
36
|
+
// the tertiary nav item object that includes path, title, and children
|
|
37
|
+
item: {
|
|
38
|
+
type: Object,
|
|
39
|
+
required: true
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
methods: {
|
|
43
|
+
linkClass(item?: NavItemObject) {
|
|
44
|
+
// default
|
|
45
|
+
let computedClass = 'py-2 lg:py-4'
|
|
46
|
+
if (!item) {
|
|
47
|
+
// if first (aka Overview)
|
|
48
|
+
computedClass = 'py-2 lg:pt-4 lg:pb-4'
|
|
49
|
+
} else if (item.children && item.children.length > 0) {
|
|
50
|
+
// if has children
|
|
51
|
+
computedClass = 'pt-2 pb-1 lg:pt-4 lg:pb-2'
|
|
52
|
+
}
|
|
53
|
+
return computedClass
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
</script>
|
|
58
|
+
<style lang="scss">
|
|
59
|
+
.NavJumpMenuContent {
|
|
60
|
+
a {
|
|
61
|
+
@apply block pl-18 pr-6 lg:pl-6 text-gray-dark;
|
|
62
|
+
|
|
63
|
+
> span {
|
|
64
|
+
@apply border-b border-transparent pb-2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&:hover {
|
|
68
|
+
> span {
|
|
69
|
+
@apply border-gray-dark text-gray-dark;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
</style>
|