@explorer-1/vue 0.2.46 → 0.2.48
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 +3 -3
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Artists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Communicators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Designers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Disruptors.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Dreamers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Educators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Innovators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Inventors.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Makers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Problem_Solvers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Robiticists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Scientists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Software_Engineers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Thinkers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImages/JPL_is__Visualizers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Artists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Communicators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Designers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Disruptors.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Dreamers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Educators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Innovators.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Inventors.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Makers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Problem_Solvers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Robiticists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Scientists.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Software_Engineers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Thinkers.jpg +0 -0
- package/public/img/SwimlaneCTA/backgroundImagesSmall/JPL_is__Visualizers.jpg +0 -0
- package/src/components/BaseButton/BaseButton.vue +1 -3
- package/src/components/HomepageMissionsCarousel/HomepageMissionsCarousel.vue +95 -91
- package/src/components/SwimlaneCTA/SwimlaneCTA.vue +8 -4
- package/src/components/TextInput/TextInput.vue +1 -1
- package/src/components/TimelineDialog/TimelineDialog.stories.js +1 -1
- package/src/components/YearTicker/YearTicker.vue +15 -7
- package/src/templates/www/PageTimeline/PageTimeline.vue +124 -102
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@explorer-1/vue",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.48",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"swiper": "^11.1.3",
|
|
27
27
|
"tailwindcss": "^3.4.3",
|
|
28
28
|
"twitter-widgets": "^2.0.0",
|
|
29
|
-
"vue": "^3.
|
|
29
|
+
"vue": "^3.5.3",
|
|
30
30
|
"vue-bind-once": "^0.2.1",
|
|
31
31
|
"vue3-compare-image": "^1.2.5",
|
|
32
32
|
"vue3-observe-visibility": "^1.0.1",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
37
|
-
"a11y-dialog": "^8.0
|
|
37
|
+
"a11y-dialog": "^8.1.0",
|
|
38
38
|
"autoprefixer": "^10.4.19",
|
|
39
39
|
"postcss": "^8.4.38",
|
|
40
40
|
"postcss-import": "^16.1.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -77,9 +77,7 @@ export default defineComponent({
|
|
|
77
77
|
// must account for <a>, <nuxt-link>, and <button> use-cases
|
|
78
78
|
theHref(): string | undefined {
|
|
79
79
|
let href = undefined
|
|
80
|
-
if (this.
|
|
81
|
-
href = this.computedTo
|
|
82
|
-
} else if (this.tag === 'a') {
|
|
80
|
+
if (this.tag === 'a') {
|
|
83
81
|
href = this.href
|
|
84
82
|
}
|
|
85
83
|
return href
|
|
@@ -1,104 +1,108 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<div
|
|
3
3
|
v-if="data"
|
|
4
|
-
class="
|
|
4
|
+
class="bg-star-pattern bg-black"
|
|
5
5
|
>
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<BaseHeading
|
|
15
|
-
v-if="data.heading"
|
|
16
|
-
level="h2"
|
|
17
|
-
class="mb-3"
|
|
18
|
-
>
|
|
19
|
-
{{ data.heading }}
|
|
20
|
-
</BaseHeading>
|
|
21
|
-
<p
|
|
22
|
-
v-if="data.summary"
|
|
23
|
-
class="text-body-md"
|
|
24
|
-
>
|
|
25
|
-
{{ data.summary }}
|
|
26
|
-
</p>
|
|
27
|
-
</div>
|
|
28
|
-
<div class="lg:order-2 xl:px-0 flex justify-end order-3 col-start-10 col-end-13 px-4">
|
|
29
|
-
<BaseLink
|
|
30
|
-
:to="{ name: 'missions' }"
|
|
31
|
-
variant="primary"
|
|
32
|
-
>
|
|
33
|
-
All Missions
|
|
34
|
-
</BaseLink>
|
|
35
|
-
</div>
|
|
36
|
-
<!-- Slider main container -->
|
|
37
|
-
<div class="lg:order-3 order-2 col-start-2 col-end-12">
|
|
38
|
-
<div
|
|
39
|
-
ref="HomepageMissionsCarousel"
|
|
40
|
-
class="swiper lg:mt-0 lg:mb-0 mb-14 mt-3"
|
|
41
|
-
>
|
|
42
|
-
<!-- Additional required wrapper -->
|
|
43
|
-
<nav
|
|
44
|
-
:aria-label="data.heading || 'Missions'"
|
|
45
|
-
class="swiper-wrapper"
|
|
6
|
+
<section
|
|
7
|
+
class="HomepageMissionsCarousel ThemeVariantDark max-w-screen-3xl mx-auto overflow-hidden text-white bg-black bg-stars"
|
|
8
|
+
>
|
|
9
|
+
<div class="lg:BaseGrid lg:py-24 pt-14 container flex flex-col pb-5 mx-auto">
|
|
10
|
+
<div class="xl:px-0 lg:col-end-8 xl:col-end-7 order-1 col-start-2 px-4">
|
|
11
|
+
<p
|
|
12
|
+
v-if="data.label"
|
|
13
|
+
class="text-subtitle text-primary edu:text-white mb-3"
|
|
46
14
|
>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
15
|
+
{{ data.label }}
|
|
16
|
+
</p>
|
|
17
|
+
<BaseHeading
|
|
18
|
+
v-if="data.heading"
|
|
19
|
+
level="h2"
|
|
20
|
+
class="mb-3"
|
|
21
|
+
>
|
|
22
|
+
{{ data.heading }}
|
|
23
|
+
</BaseHeading>
|
|
24
|
+
<p
|
|
25
|
+
v-if="data.summary"
|
|
26
|
+
class="text-body-md"
|
|
27
|
+
>
|
|
28
|
+
{{ data.summary }}
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="lg:order-2 xl:px-0 flex justify-end order-3 col-start-10 col-end-13 px-4">
|
|
32
|
+
<BaseLink
|
|
33
|
+
:to="{ name: 'missions' }"
|
|
34
|
+
variant="primary"
|
|
35
|
+
>
|
|
36
|
+
{{ `All Missions` }}
|
|
37
|
+
</BaseLink>
|
|
38
|
+
</div>
|
|
39
|
+
<!-- Slider main container -->
|
|
40
|
+
<div class="lg:order-3 order-2 col-start-2 col-end-12">
|
|
41
|
+
<div
|
|
42
|
+
ref="HomepageMissionsCarousel"
|
|
43
|
+
class="swiper lg:mt-0 lg:mb-0 mb-14 mt-3"
|
|
44
|
+
>
|
|
45
|
+
<!-- Additional required wrapper -->
|
|
46
|
+
<nav
|
|
47
|
+
:aria-label="data.heading || 'Missions'"
|
|
48
|
+
class="swiper-wrapper"
|
|
49
|
+
>
|
|
50
|
+
<!-- slide -->
|
|
51
|
+
<HomepageMissionsCarouselItem
|
|
52
|
+
v-for="(item, index) in data.targets"
|
|
53
|
+
:key="index"
|
|
54
|
+
:data="item"
|
|
55
|
+
class="swiper-slide"
|
|
56
|
+
/>
|
|
57
|
+
</nav>
|
|
58
|
+
<!-- swiper navigation -->
|
|
59
|
+
<div class="swiper-navigation xl:block absolute top-0 left-0 hidden w-full">
|
|
60
|
+
<div class="top-1/2 absolute left-0 z-30">
|
|
61
|
+
<BaseButton
|
|
62
|
+
class="swiper-prev xl:text-base -ml-16"
|
|
63
|
+
:aria-label="data.heading + ' - Previous slide'"
|
|
64
|
+
>
|
|
65
|
+
<template #icon>
|
|
66
|
+
<span
|
|
67
|
+
class="arrow-wrapper"
|
|
68
|
+
aria-hidden="true"
|
|
69
|
+
>
|
|
70
|
+
<span class="arrow">
|
|
71
|
+
<IconPrev />
|
|
72
|
+
</span>
|
|
73
|
+
<span class="arrow-fixed">
|
|
74
|
+
<IconPrev />
|
|
75
|
+
</span>
|
|
89
76
|
</span>
|
|
90
|
-
|
|
91
|
-
|
|
77
|
+
</template>
|
|
78
|
+
</BaseButton>
|
|
79
|
+
</div>
|
|
80
|
+
<div class="top-1/2 absolute right-0 z-30">
|
|
81
|
+
<BaseButton
|
|
82
|
+
class="swiper-next xl:text-base -mr-16"
|
|
83
|
+
:aria-label="data.heading + ' - Next slide'"
|
|
84
|
+
>
|
|
85
|
+
<template #icon>
|
|
86
|
+
<span
|
|
87
|
+
class="arrow-wrapper"
|
|
88
|
+
aria-hidden="true"
|
|
89
|
+
>
|
|
90
|
+
<span class="arrow">
|
|
91
|
+
<IconNext />
|
|
92
|
+
</span>
|
|
93
|
+
<span class="arrow-fixed">
|
|
94
|
+
<IconNext />
|
|
95
|
+
</span>
|
|
92
96
|
</span>
|
|
93
|
-
</
|
|
94
|
-
</
|
|
95
|
-
</
|
|
97
|
+
</template>
|
|
98
|
+
</BaseButton>
|
|
99
|
+
</div>
|
|
96
100
|
</div>
|
|
97
101
|
</div>
|
|
98
102
|
</div>
|
|
99
103
|
</div>
|
|
100
|
-
</
|
|
101
|
-
</
|
|
104
|
+
</section>
|
|
105
|
+
</div>
|
|
102
106
|
</template>
|
|
103
107
|
<script lang="ts">
|
|
104
108
|
import { defineComponent } from 'vue'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="justify-items-center flex w-full">
|
|
2
|
+
<div class="justify-items-center flex w-full relative overflow-hidden">
|
|
3
3
|
<BaseLink
|
|
4
4
|
v-if="targetLink"
|
|
5
5
|
class="w-full"
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
</template>
|
|
43
43
|
</div>
|
|
44
44
|
<div class="lg:p-1 text-contrast relative z-20 pt-2 pl-0">
|
|
45
|
-
<p class="text-secondary lg:text-7xl mb-0 text-4xl font-medium">
|
|
45
|
+
<p class="text-secondary text-white lg:text-7xl mb-0 text-4xl font-medium">
|
|
46
|
+
is a place for
|
|
47
|
+
</p>
|
|
46
48
|
</div>
|
|
47
49
|
</div>
|
|
48
50
|
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
:class="'SwimlaneCTA lg:hidden block' + computedClass"
|
|
67
69
|
>
|
|
68
70
|
<div
|
|
69
|
-
class="lg:flex-row lg:pr-12 lg:py-5 flex flex-col justify-center w-full px-5 py-6 bg-black bg-opacity-25"
|
|
71
|
+
class="lg:flex-row lg:pr-12 lg:py-5 flex flex-col justify-center w-full px-5 py-6 bg-black bg-opacity-25 font-primary"
|
|
70
72
|
>
|
|
71
73
|
<div class="lg:flex-row lg:pr-3 lg:pb-0 flex flex-col items-center justify-center pb-2">
|
|
72
74
|
<div class="relative z-20 p-2 pl-0">
|
|
@@ -92,7 +94,9 @@
|
|
|
92
94
|
</template>
|
|
93
95
|
</div>
|
|
94
96
|
<div class="lg:p-1 relative z-20 pt-2 pl-0">
|
|
95
|
-
<p
|
|
97
|
+
<p
|
|
98
|
+
class="text-secondary text-white text-contrast lg:text-7xl mb-0 text-4xl font-medium"
|
|
99
|
+
>
|
|
96
100
|
is a place for
|
|
97
101
|
</p>
|
|
98
102
|
</div>
|
|
@@ -39,7 +39,7 @@ export const BaseStory = {
|
|
|
39
39
|
setup() {
|
|
40
40
|
return { args }
|
|
41
41
|
},
|
|
42
|
-
template: `<div>
|
|
42
|
+
template: `<div style="min-height: 80vh">
|
|
43
43
|
<button type="button" :data-a11y-dialog-show="args.data.id">Open the dialog</button>
|
|
44
44
|
<TimelineDialog :data="args.data" :dialog-box-class="args.dialogBoxClass"></TimelineDialog>
|
|
45
45
|
</div>`
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
+
v-if="mounted"
|
|
3
4
|
class="YearTicker"
|
|
4
5
|
:style="`--duration:${duration}ms`"
|
|
5
6
|
>
|
|
@@ -8,17 +9,19 @@
|
|
|
8
9
|
v-for="(digit, index) in Array.from(targetYear)"
|
|
9
10
|
:key="index"
|
|
10
11
|
:name="animation"
|
|
11
|
-
|
|
12
|
+
mode="out-in"
|
|
13
|
+
tag="span"
|
|
12
14
|
>
|
|
13
15
|
<!-- Key by digit so there can be two digits rendered at the same time. -->
|
|
14
16
|
<span
|
|
15
|
-
:key="digit"
|
|
17
|
+
:key="digit + index"
|
|
16
18
|
class="Digit"
|
|
17
19
|
>{{ digit }}</span
|
|
18
20
|
>
|
|
19
21
|
</transition-group>
|
|
20
22
|
</div>
|
|
21
23
|
</template>
|
|
24
|
+
|
|
22
25
|
<script lang="ts">
|
|
23
26
|
import { defineComponent } from 'vue'
|
|
24
27
|
|
|
@@ -34,17 +37,22 @@ export default defineComponent({
|
|
|
34
37
|
return {
|
|
35
38
|
year: this.targetYear,
|
|
36
39
|
animation: 'digits-increment',
|
|
37
|
-
duration: 100
|
|
40
|
+
duration: 100,
|
|
41
|
+
mounted: false // Track if the component is mounted
|
|
38
42
|
}
|
|
39
43
|
},
|
|
40
44
|
watch: {
|
|
41
|
-
targetYear(newYear) {
|
|
42
|
-
this.animation =
|
|
45
|
+
targetYear(newYear, oldYear) {
|
|
46
|
+
this.animation = newYear > oldYear ? 'digits-increment' : 'digits-decrement'
|
|
43
47
|
this.year = newYear
|
|
44
48
|
}
|
|
49
|
+
},
|
|
50
|
+
mounted() {
|
|
51
|
+
this.mounted = true // Set mounted to true after mounting
|
|
45
52
|
}
|
|
46
53
|
})
|
|
47
54
|
</script>
|
|
55
|
+
|
|
48
56
|
<style lang="scss">
|
|
49
57
|
.YearTicker {
|
|
50
58
|
@apply sticky transform text-gray-light-mid translate-x-0.5 md:translate-x-0 ml-7 md:ml-8 lg:ml-30 pt-10 md:pt-5;
|
|
@@ -78,7 +86,7 @@ export default defineComponent({
|
|
|
78
86
|
|
|
79
87
|
.header-sticky-showing & {
|
|
80
88
|
// For the mobile viewport, offset by the height of the top header and NavSecondary combined.
|
|
81
|
-
top: calc(theme('spacing.18') + theme('spacing.16') + var(--top-offset));
|
|
89
|
+
top: calc(theme('spacing.18') + theme('spacing.16') + var (--top-offset));
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
&::after {
|
|
@@ -103,7 +111,6 @@ export default defineComponent({
|
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
.Digit {
|
|
106
|
-
// Force all digits in the same cell so they superpose.
|
|
107
114
|
grid-area: 1 / 1 / 1 / 1;
|
|
108
115
|
transition: transform var(--duration);
|
|
109
116
|
transform: translateY(0);
|
|
@@ -112,6 +119,7 @@ export default defineComponent({
|
|
|
112
119
|
transition-duration: 0.1ms;
|
|
113
120
|
}
|
|
114
121
|
}
|
|
122
|
+
|
|
115
123
|
// transitions
|
|
116
124
|
.digits-decrement-enter-active {
|
|
117
125
|
transform: translateY(100%);
|
|
@@ -1,114 +1,29 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
v-if="data"
|
|
4
|
-
class="-nav-offset"
|
|
5
|
-
>
|
|
6
|
-
<HeroLarge
|
|
7
|
-
:title="data.heroTitle"
|
|
8
|
-
:summary="data.heroSummary"
|
|
9
|
-
:image="data.heroImage"
|
|
10
|
-
has-overlay
|
|
11
|
-
/>
|
|
12
|
-
<!--
|
|
13
|
-
/**
|
|
14
|
-
* This page contains a lot of overlapping elements. Layers from highest to lowest:
|
|
15
|
-
* - TimelineDialog
|
|
16
|
-
* - Dropdown menus within NavSecondary
|
|
17
|
-
* - BackToTop, Main navigation, NavSecondary
|
|
18
|
-
* - (YearTicker on mobile viewport)
|
|
19
|
-
* - Milestone cards (BlockMilestone / BlockCircleImageCard)
|
|
20
|
-
* - VerticalLine
|
|
21
|
-
* - Milestone background images
|
|
22
|
-
* - (YearTicker on desktop viewport)
|
|
23
|
-
*/ -->
|
|
24
|
-
<NavSecondary>
|
|
25
|
-
<!-- Use a fixed height to simplify sticky positioning. -->
|
|
26
|
-
<div class="w-full flex gap-4 align-content h-16">
|
|
27
|
-
<!-- Use a SearchSelectMenu for consistency with the "sort by" dropdown. -->
|
|
28
|
-
<SearchSelectMenu
|
|
29
|
-
v-model="jumpTo"
|
|
30
|
-
v-model:select-value="jumpTo"
|
|
31
|
-
class="flex"
|
|
32
|
-
:options="getJumpDecades()"
|
|
33
|
-
title="Jump to"
|
|
34
|
-
group-key="jumpTo"
|
|
35
|
-
/>
|
|
36
|
-
<SearchSelectMenu
|
|
37
|
-
v-model="sortBy"
|
|
38
|
-
v-model:select-value="sortBy"
|
|
39
|
-
class="flex"
|
|
40
|
-
:options="sortByOptions"
|
|
41
|
-
title="Sort by"
|
|
42
|
-
group-key="sortBy"
|
|
43
|
-
/>
|
|
44
|
-
</div>
|
|
45
|
-
</NavSecondary>
|
|
46
|
-
<YearTicker :target-year="currentYear as string" />
|
|
47
|
-
<h2 class="sr-only">Milestones</h2>
|
|
48
|
-
<ParallaxContainer
|
|
49
|
-
class="MilestoneList BaseGrid"
|
|
50
|
-
:style="{ '--rows': milestones.length }"
|
|
51
|
-
>
|
|
52
|
-
<div
|
|
53
|
-
v-for="(milestone, index) in milestones"
|
|
54
|
-
:id="`milestone-${milestone.date}`"
|
|
55
|
-
:key="`${milestone.id}-fg`"
|
|
56
|
-
class="MilestoneListItem"
|
|
57
|
-
:style="{ '--row': index + 1 }"
|
|
58
|
-
:data-milestone-year="milestone.date.split('-')[0]"
|
|
59
|
-
>
|
|
60
|
-
<ParallaxElement
|
|
61
|
-
v-if="milestone.backgroundImage"
|
|
62
|
-
class="MilestoneImageWrapper"
|
|
63
|
-
:factor="index % 2 === 0 ? 0.18 : 0.22"
|
|
64
|
-
:offset="index * 80"
|
|
65
|
-
>
|
|
66
|
-
<img
|
|
67
|
-
class="MilestoneImage"
|
|
68
|
-
:src="milestone.backgroundImage.src.url"
|
|
69
|
-
:width="milestone.backgroundImage.src.width"
|
|
70
|
-
:height="milestone.backgroundImage.src.height"
|
|
71
|
-
:srcset="`${milestone.backgroundImage.screenMd.url} ${milestone.backgroundImage.screenMd.width}w ${milestone.backgroundImage.src.url} ${milestone.backgroundImage.src.width}w`"
|
|
72
|
-
:style="{
|
|
73
|
-
// Shift images left or right based on column, and then by a variable amount to create a staggered effect.
|
|
74
|
-
'--x-translate': `${(index % 2 === 0 ? 180 : -130) + 10 * (index % 3)}%`
|
|
75
|
-
}"
|
|
76
|
-
alt=""
|
|
77
|
-
/>
|
|
78
|
-
</ParallaxElement>
|
|
79
|
-
<BlockMilestone
|
|
80
|
-
:data="milestone"
|
|
81
|
-
:handle-click="showMilestone"
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<div class="VerticalLine"></div>
|
|
85
|
-
</ParallaxContainer>
|
|
86
|
-
<BackToTop
|
|
87
|
-
class="fixed right-10 bottom-10"
|
|
88
|
-
:threshold="900"
|
|
89
|
-
@click="handleBackToTop()"
|
|
90
|
-
/>
|
|
91
|
-
|
|
92
|
-
<TimelineDialog
|
|
93
|
-
v-if="activeMilestone"
|
|
94
|
-
:data="activeMilestone"
|
|
95
|
-
dialog-box-class="sm:max-w-xl md:max-w-3xl"
|
|
96
|
-
@hide="() => (activeMilestone = null)"
|
|
97
|
-
></TimelineDialog>
|
|
98
|
-
</div>
|
|
99
|
-
</template>
|
|
100
1
|
<script lang="ts">
|
|
2
|
+
// PageTimeline.vue - Timeline component for displaying milestones.
|
|
101
3
|
import { defineComponent, type PropType } from 'vue'
|
|
102
4
|
import BackToTop from './../../../components/BackToTop/BackToTop.vue'
|
|
103
5
|
import BlockMilestone, { Milestone } from './BlockMilestone.vue'
|
|
104
6
|
import HeroLarge from './../../../components/HeroLarge/HeroLarge.vue'
|
|
105
7
|
import NavSecondary from './../../../components/NavSecondary/NavSecondary.vue'
|
|
8
|
+
// Use a SearchSelectMenu for consistency with the "sort by" dropdown.
|
|
106
9
|
import SearchSelectMenu from './../../../components/SearchSelectMenu/SearchSelectMenu.vue'
|
|
107
10
|
import TimelineDialog from './../../../components/TimelineDialog/TimelineDialog.vue'
|
|
108
11
|
import YearTicker from './../../../components/YearTicker/YearTicker.vue'
|
|
109
12
|
import ParallaxContainer from './../../../components/ParallaxContainer/ParallaxContainer.vue'
|
|
110
13
|
import ParallaxElement from './../../../components/ParallaxElement/ParallaxElement.vue'
|
|
111
14
|
|
|
15
|
+
/**
|
|
16
|
+
* This page contains a lot of overlapping elements. Layers from highest to lowest:
|
|
17
|
+
* - TimelineDialog
|
|
18
|
+
* - Dropdown menus within NavSecondary
|
|
19
|
+
* - BackToTop, Main navigation, NavSecondary
|
|
20
|
+
* - (YearTicker on mobile viewport)
|
|
21
|
+
* - Milestone cards (BlockMilestone / BlockCircleImageCard)
|
|
22
|
+
* - VerticalLine
|
|
23
|
+
* - Milestone background images
|
|
24
|
+
* - (YearTicker on desktop viewport)
|
|
25
|
+
*/
|
|
26
|
+
|
|
112
27
|
type SortBy = '' | 'latestDate' | 'oldestDate'
|
|
113
28
|
|
|
114
29
|
type Decades = {
|
|
@@ -243,7 +158,8 @@ export default defineComponent({
|
|
|
243
158
|
},
|
|
244
159
|
getJumpDecades() {
|
|
245
160
|
const decades: Decades = {
|
|
246
|
-
|
|
161
|
+
// uppercase string to avoid conflict with the lowercase 's' in the decade
|
|
162
|
+
TOP: ''
|
|
247
163
|
}
|
|
248
164
|
|
|
249
165
|
this.milestones.forEach((milestone) => {
|
|
@@ -301,16 +217,112 @@ export default defineComponent({
|
|
|
301
217
|
}
|
|
302
218
|
})
|
|
303
219
|
</script>
|
|
220
|
+
|
|
221
|
+
<template>
|
|
222
|
+
<div
|
|
223
|
+
v-if="data"
|
|
224
|
+
class="-nav-offset"
|
|
225
|
+
>
|
|
226
|
+
<HeroLarge
|
|
227
|
+
:title="data.heroTitle"
|
|
228
|
+
:summary="data.heroSummary"
|
|
229
|
+
:image="data.heroImage"
|
|
230
|
+
has-overlay
|
|
231
|
+
/>
|
|
232
|
+
|
|
233
|
+
<NavSecondary>
|
|
234
|
+
<!-- Use a fixed height to simplify sticky positioning. -->
|
|
235
|
+
<div class="w-full flex gap-4 align-content h-16">
|
|
236
|
+
<SearchSelectMenu
|
|
237
|
+
v-model="jumpTo"
|
|
238
|
+
v-model:select-value="jumpTo"
|
|
239
|
+
class="flex"
|
|
240
|
+
:options="getJumpDecades()"
|
|
241
|
+
title="JUMP TO"
|
|
242
|
+
group-key="jumpTo"
|
|
243
|
+
/>
|
|
244
|
+
<SearchSelectMenu
|
|
245
|
+
v-model="sortBy"
|
|
246
|
+
v-model:select-value="sortBy"
|
|
247
|
+
class="flex"
|
|
248
|
+
:options="sortByOptions"
|
|
249
|
+
title="SORT BY"
|
|
250
|
+
group-key="sortBy"
|
|
251
|
+
/>
|
|
252
|
+
</div>
|
|
253
|
+
</NavSecondary>
|
|
254
|
+
<YearTicker :target-year="currentYear as string" />
|
|
255
|
+
<h2 class="sr-only">Milestones</h2>
|
|
256
|
+
<ParallaxContainer
|
|
257
|
+
class="MilestoneList BaseGrid"
|
|
258
|
+
:style="{ '--rows': milestones.length }"
|
|
259
|
+
>
|
|
260
|
+
<div
|
|
261
|
+
v-for="(milestone, index) in milestones"
|
|
262
|
+
:id="`milestone-${milestone.date}`"
|
|
263
|
+
:key="`${milestone.id}-fg`"
|
|
264
|
+
class="MilestoneListItem"
|
|
265
|
+
:style="{ '--row': index + 1 }"
|
|
266
|
+
:data-milestone-year="milestone.date.split('-')[0]"
|
|
267
|
+
>
|
|
268
|
+
<ParallaxElement
|
|
269
|
+
v-if="milestone.backgroundImage"
|
|
270
|
+
class="MilestoneImageWrapper"
|
|
271
|
+
:factor="0.18"
|
|
272
|
+
:offset="index * 80"
|
|
273
|
+
>
|
|
274
|
+
<img
|
|
275
|
+
class="MilestoneImage"
|
|
276
|
+
:src="milestone.backgroundImage.src.url"
|
|
277
|
+
:width="milestone.backgroundImage.src.width"
|
|
278
|
+
:height="milestone.backgroundImage.src.height"
|
|
279
|
+
:srcset="`${milestone.backgroundImage.screenMd.url} ${milestone.backgroundImage.screenMd.width}w ${milestone.backgroundImage.src.url} ${milestone.backgroundImage.src.width}w`"
|
|
280
|
+
:style="{
|
|
281
|
+
// Shift images left or right based on column, and then by a variable amount to create a staggered effect.
|
|
282
|
+
'--x-translate': `${(index % 2 === 0 ? 180 : -130) + 10 * (index % 3)}%`
|
|
283
|
+
}"
|
|
284
|
+
alt=""
|
|
285
|
+
/>
|
|
286
|
+
</ParallaxElement>
|
|
287
|
+
<BlockMilestone
|
|
288
|
+
:data="milestone"
|
|
289
|
+
:handle-click="showMilestone"
|
|
290
|
+
/>
|
|
291
|
+
</div>
|
|
292
|
+
<div class="VerticalLine"></div>
|
|
293
|
+
</ParallaxContainer>
|
|
294
|
+
<BackToTop
|
|
295
|
+
class="fixed right-10 bottom-10"
|
|
296
|
+
:threshold="900"
|
|
297
|
+
@click="handleBackToTop()"
|
|
298
|
+
/>
|
|
299
|
+
|
|
300
|
+
<TimelineDialog
|
|
301
|
+
v-if="activeMilestone"
|
|
302
|
+
:data="activeMilestone"
|
|
303
|
+
dialog-box-class="sm:max-w-xl md:max-w-3xl"
|
|
304
|
+
@hide="() => (activeMilestone = null)"
|
|
305
|
+
></TimelineDialog>
|
|
306
|
+
</div>
|
|
307
|
+
</template>
|
|
308
|
+
|
|
304
309
|
<style lang="scss">
|
|
305
310
|
$line-width: 2px;
|
|
306
311
|
$column-gap-width: 1.5rem;
|
|
307
312
|
|
|
313
|
+
// makes the years able to have a lowercase 's' in the decade
|
|
314
|
+
select {
|
|
315
|
+
&#select_jumpTo {
|
|
316
|
+
text-transform: none;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
308
320
|
.NavSecondary {
|
|
309
321
|
@apply block;
|
|
310
322
|
}
|
|
311
323
|
|
|
312
324
|
.MilestoneList {
|
|
313
|
-
@apply gap-y-0;
|
|
325
|
+
@apply gap-y-0 max-w-screen-4xl mx-auto;
|
|
314
326
|
|
|
315
327
|
// Offset the list up so the vertical line starts from the secondary nav.
|
|
316
328
|
@screen md {
|
|
@@ -347,6 +359,10 @@ $column-gap-width: 1.5rem;
|
|
|
347
359
|
transform: translateX($line-width);
|
|
348
360
|
grid-row: var(--row);
|
|
349
361
|
|
|
362
|
+
&:nth-of-type(1) {
|
|
363
|
+
@apply md:pt-20;
|
|
364
|
+
}
|
|
365
|
+
|
|
350
366
|
&:nth-of-type(even) {
|
|
351
367
|
@apply md:justify-start md:col-start-7;
|
|
352
368
|
|
|
@@ -369,7 +385,7 @@ $column-gap-width: 1.5rem;
|
|
|
369
385
|
}
|
|
370
386
|
|
|
371
387
|
.VerticalLine {
|
|
372
|
-
@apply border-l border-r border-jpl-red top-5 md:top-
|
|
388
|
+
@apply border-l border-r border-jpl-red top-5 md:top-2 bottom-0 col-start-3 md:col-start-7 mb-12;
|
|
373
389
|
|
|
374
390
|
// Use CSS grid positioning rather than position absolute within relative,
|
|
375
391
|
// so we don’t create a new stacking context within the ParallaxContainer.
|
|
@@ -384,5 +400,11 @@ $column-gap-width: 1.5rem;
|
|
|
384
400
|
border-image-slice: 1;
|
|
385
401
|
transform: translateX(-1 * $column-gap-width);
|
|
386
402
|
}
|
|
403
|
+
|
|
404
|
+
&::before {
|
|
405
|
+
@apply absolute -top-px -left-2px w-1 h-30 bg-gradient-to-b from-white to-transparent;
|
|
406
|
+
|
|
407
|
+
content: '';
|
|
408
|
+
}
|
|
387
409
|
}
|
|
388
410
|
</style>
|