@explorer-1/vue 0.0.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 (371) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/components.d.ts +215 -0
  4. package/index.html +18 -0
  5. package/lib/main.ts +78 -0
  6. package/package.json +54 -0
  7. package/postcss.config.js +7 -0
  8. package/public/edu/.gitkeep +0 -0
  9. package/public/edu/explorer-1/bg-stars-edu.png +0 -0
  10. package/public/edu/explorer-1/bg-stars.jpg +0 -0
  11. package/public/explorer-1/bg-stars-edu.png +0 -0
  12. package/public/explorer-1/bg-stars.jpg +0 -0
  13. package/src/App.vue +30 -0
  14. package/src/assets/fonts/README.md +12 -0
  15. package/src/assets/fonts/archivo-narrow/ArchivoNarrow-Bold.woff2 +0 -0
  16. package/src/assets/fonts/archivo-narrow/ArchivoNarrow-BoldItalic.woff2 +0 -0
  17. package/src/assets/fonts/archivo-narrow/ArchivoNarrow-SemiBold.woff2 +0 -0
  18. package/src/assets/fonts/archivo-narrow/ArchivoNarrow-SemiBoldItalic.woff2 +0 -0
  19. package/src/assets/fonts/metropolis/Metropolis-Bold.woff2 +0 -0
  20. package/src/assets/fonts/metropolis/Metropolis-BoldItalic.woff2 +0 -0
  21. package/src/assets/fonts/metropolis/Metropolis-ExtraBold.woff2 +0 -0
  22. package/src/assets/fonts/metropolis/Metropolis-Medium.woff2 +0 -0
  23. package/src/assets/fonts/metropolis/Metropolis-MediumItalic.woff2 +0 -0
  24. package/src/assets/fonts/metropolis/Metropolis-Regular.woff2 +0 -0
  25. package/src/assets/fonts/metropolis/Metropolis-RegularItalic.woff2 +0 -0
  26. package/src/assets/fonts/metropolis/Metropolis-SemiBold.woff2 +0 -0
  27. package/src/assets/fonts/metropolis/Metropolis-SemiBoldItalic.woff2 +0 -0
  28. package/src/assets/scss/styles.scss +1 -0
  29. package/src/components/AsteroidWatchWidget/AsteroidWatchWidget.stories.js +156 -0
  30. package/src/components/AsteroidWatchWidget/AsteroidWatchWidget.vue +156 -0
  31. package/src/components/BackToTop/BackToTop.stories.js +24 -0
  32. package/src/components/BackToTop/BackToTop.vue +76 -0
  33. package/src/components/BaseAudio/BaseAudio.stories.js +29 -0
  34. package/src/components/BaseAudio/BaseAudio.vue +359 -0
  35. package/src/components/BaseButton/BaseButton.stories.ts +65 -0
  36. package/src/components/BaseButton/BaseButton.vue +114 -0
  37. package/src/components/BaseCheckboxGroup/BaseCheckboxGroup.stories.mdx +68 -0
  38. package/src/components/BaseCheckboxGroup/BaseCheckboxGroup.vue +101 -0
  39. package/src/components/BaseHeading/BaseHeading.stories.js +75 -0
  40. package/src/components/BaseHeading/BaseHeading.vue +58 -0
  41. package/src/components/BaseImage/BaseImage.stories.ts +52 -0
  42. package/src/components/BaseImage/BaseImage.vue +120 -0
  43. package/src/components/BaseImageCaption/BaseImageCaption.stories.js +27 -0
  44. package/src/components/BaseImageCaption/BaseImageCaption.vue +51 -0
  45. package/src/components/BaseImagePlaceholder/BaseImagePlaceholder.stories.js +73 -0
  46. package/src/components/BaseImagePlaceholder/BaseImagePlaceholder.vue +90 -0
  47. package/src/components/BaseLightboxCloseButton/BaseLightboxCloseButton.vue +45 -0
  48. package/src/components/BaseLightboxOpenButton/BaseLightboxOpenButton.vue +46 -0
  49. package/src/components/BaseLink/BaseLink.stories.js +47 -0
  50. package/src/components/BaseLink/BaseLink.vue +227 -0
  51. package/src/components/BaseModal/BaseModal.stories.js +90 -0
  52. package/src/components/BaseModal/BaseModal.vue +54 -0
  53. package/src/components/BaseModal/BaseModalDialog.vue +59 -0
  54. package/src/components/BasePlaceholder/BasePlaceholder.stories.js +29 -0
  55. package/src/components/BasePlaceholder/BasePlaceholder.vue +30 -0
  56. package/src/components/BaseRadioGroup/BaseRadioGroup.stories.mdx +68 -0
  57. package/src/components/BaseRadioGroup/BaseRadioGroup.vue +102 -0
  58. package/src/components/BaseSwimlane/BaseSwimlane.stories.mdx +64 -0
  59. package/src/components/BaseSwimlane/BaseSwimlane.vue +204 -0
  60. package/src/components/BaseTag/BaseTag.stories.js +34 -0
  61. package/src/components/BaseTag/BaseTag.vue +36 -0
  62. package/src/components/BaseTimer/BaseTimer.stories.js +78 -0
  63. package/src/components/BaseTimer/BaseTimer.test.js +15 -0
  64. package/src/components/BaseTimer/BaseTimer.vue +270 -0
  65. package/src/components/BaseUnitToggle/BaseUnitToggle.stories.js +86 -0
  66. package/src/components/BaseUnitToggle/BaseUnitToggle.test.js +26 -0
  67. package/src/components/BaseUnitToggle/BaseUnitToggle.vue +255 -0
  68. package/src/components/BaseVideo/BaseVideo.stories.js +31 -0
  69. package/src/components/BaseVideo/BaseVideo.vue +73 -0
  70. package/src/components/BlockAnchor/BlockAnchor.vue +38 -0
  71. package/src/components/BlockAudio/BlockAudio.stories.js +29 -0
  72. package/src/components/BlockAudio/BlockAudio.vue +78 -0
  73. package/src/components/BlockCard/BlockCard.stories.js +24 -0
  74. package/src/components/BlockCard/BlockCard.vue +88 -0
  75. package/src/components/BlockCardGroup/BlockCardGroup.stories.js +71 -0
  76. package/src/components/BlockCardGroup/BlockCardGroup.vue +61 -0
  77. package/src/components/BlockCircleImageCard/BlockCircleImageCard.stories.js +55 -0
  78. package/src/components/BlockCircleImageCard/BlockCircleImageCard.vue +120 -0
  79. package/src/components/BlockCta/BlockCta.stories.js +35 -0
  80. package/src/components/BlockCta/BlockCta.vue +55 -0
  81. package/src/components/BlockHeading/BlockHeading.stories.js +22 -0
  82. package/src/components/BlockHeading/BlockHeading.vue +27 -0
  83. package/src/components/BlockIframeEmbed/BlockIframeEmbed.stories.js +40 -0
  84. package/src/components/BlockIframeEmbed/BlockIframeEmbed.vue +84 -0
  85. package/src/components/BlockImage/BlockImage.stories.js +137 -0
  86. package/src/components/BlockImage/BlockImage.vue +48 -0
  87. package/src/components/BlockImage/BlockImageFullBleed.vue +119 -0
  88. package/src/components/BlockImage/BlockImageStandard.vue +106 -0
  89. package/src/components/BlockImageCarousel/BlockImageCarousel.stories.js +108 -0
  90. package/src/components/BlockImageCarousel/BlockImageCarousel.vue +201 -0
  91. package/src/components/BlockImageCarouselItem/BlockImageCarouselItem.stories.js +63 -0
  92. package/src/components/BlockImageCarouselItem/BlockImageCarouselItem.vue +120 -0
  93. package/src/components/BlockImageComparison/BlockImageComparison.stories.js +46 -0
  94. package/src/components/BlockImageComparison/BlockImageComparison.vue +59 -0
  95. package/src/components/BlockImageGallery/BlockImageGallery.stories.js +55 -0
  96. package/src/components/BlockImageGallery/BlockImageGallery.vue +128 -0
  97. package/src/components/BlockInlineImage/BlockInlineImage.stories.js +68 -0
  98. package/src/components/BlockInlineImage/BlockInlineImage.vue +124 -0
  99. package/src/components/BlockKeyPoints/BlockKeyPoints.stories.js +28 -0
  100. package/src/components/BlockKeyPoints/BlockKeyPoints.vue +48 -0
  101. package/src/components/BlockLinkCard/BlockLinkCard.stories.js +102 -0
  102. package/src/components/BlockLinkCard/BlockLinkCard.vue +197 -0
  103. package/src/components/BlockLinkCarousel/BlockLinkCarousel.stories.js +217 -0
  104. package/src/components/BlockLinkCarousel/BlockLinkCarousel.vue +68 -0
  105. package/src/components/BlockLinkTile/BlockLinkTile.stories.js +72 -0
  106. package/src/components/BlockLinkTile/BlockLinkTile.vue +193 -0
  107. package/src/components/BlockListCards/BlockListCards.stories.js +69 -0
  108. package/src/components/BlockListCards/BlockListCards.vue +129 -0
  109. package/src/components/BlockQuote/BlockQuote.stories.js +84 -0
  110. package/src/components/BlockQuote/BlockQuote.vue +87 -0
  111. package/src/components/BlockRelatedLinks/BlockRelatedLinks.stories.js +60 -0
  112. package/src/components/BlockRelatedLinks/BlockRelatedLinks.vue +77 -0
  113. package/src/components/BlockRelatedLinks/RelatedLink.vue +85 -0
  114. package/src/components/BlockStreamfield/BlockStreamfield.stories.js +88 -0
  115. package/src/components/BlockStreamfield/BlockStreamfield.vue +333 -0
  116. package/src/components/BlockTable/BlockTable.stories.js +20 -0
  117. package/src/components/BlockTable/BlockTable.vue +73 -0
  118. package/src/components/BlockTeaser/BlockTeaser.stories.js +74 -0
  119. package/src/components/BlockTeaser/BlockTeaser.test.js +12 -0
  120. package/src/components/BlockTeaser/BlockTeaser.vue +174 -0
  121. package/src/components/BlockText/BlockText.stories.js +21 -0
  122. package/src/components/BlockText/BlockText.vue +44 -0
  123. package/src/components/BlockTwitterEmbed/BlockTwitterEmbed.stories.js +19 -0
  124. package/src/components/BlockTwitterEmbed/BlockTwitterEmbed.vue +61 -0
  125. package/src/components/BlockVideo/BlockVideo.stories.js +23 -0
  126. package/src/components/BlockVideo/BlockVideo.vue +41 -0
  127. package/src/components/BlockVideoEmbed/BlockVideoEmbed.stories.js +20 -0
  128. package/src/components/BlockVideoEmbed/BlockVideoEmbed.vue +71 -0
  129. package/src/components/CalendarButton/CalendarButton.stories.js +36 -0
  130. package/src/components/CalendarButton/CalendarButton.vue +86 -0
  131. package/src/components/DetailHeadline/DetailHeadline.stories.js +48 -0
  132. package/src/components/DetailHeadline/DetailHeadline.vue +143 -0
  133. package/src/components/DsnWidget/DsnWidget.stories.js +29 -0
  134. package/src/components/DsnWidget/DsnWidget.vue +96 -0
  135. package/src/components/EventCard/EventCard.vue +188 -0
  136. package/src/components/EventDetailHero/EventDetailHero.stories.js +53 -0
  137. package/src/components/EventDetailHero/EventDetailHero.vue +64 -0
  138. package/src/components/FormContact/FormContact.stories.js +16 -0
  139. package/src/components/FormContact/FormContact.vue +202 -0
  140. package/src/components/FormNewsletterSignup/FormNewsletterSignup.stories.js +16 -0
  141. package/src/components/FormNewsletterSignup/FormNewsletterSignup.vue +355 -0
  142. package/src/components/HeroLarge/HeroLarge.stories.js +46 -0
  143. package/src/components/HeroLarge/HeroLarge.vue +93 -0
  144. package/src/components/HeroListingIndex/HeroListingIndex.stories.js +156 -0
  145. package/src/components/HeroListingIndex/HeroListingIndex.vue +80 -0
  146. package/src/components/HeroMedia/HeroMedia.stories.js +135 -0
  147. package/src/components/HeroMedia/HeroMedia.vue +174 -0
  148. package/src/components/HeroMedium/HeroMedium.stories.js +73 -0
  149. package/src/components/HeroMedium/HeroMedium.vue +166 -0
  150. package/src/components/HomepageCarousel/HomepageCarousel.stories.js +112 -0
  151. package/src/components/HomepageCarousel/HomepageCarousel.vue +382 -0
  152. package/src/components/HomepageCarouselItem/HomepageCarouselItem.stories.js +60 -0
  153. package/src/components/HomepageCarouselItem/HomepageCarouselItem.vue +168 -0
  154. package/src/components/HomepageEmbedBlock/HomepageEmbedBlock.stories.js +35 -0
  155. package/src/components/HomepageEmbedBlock/HomepageEmbedBlock.vue +39 -0
  156. package/src/components/HomepageFeaturedRobot/HomepageFeaturedRobot.stories.js +93 -0
  157. package/src/components/HomepageFeaturedRobot/HomepageFeaturedRobot.vue +129 -0
  158. package/src/components/HomepageMissionsCarousel/HomepageMissionsCarousel.stories.js +153 -0
  159. package/src/components/HomepageMissionsCarousel/HomepageMissionsCarousel.vue +282 -0
  160. package/src/components/HomepageMissionsCarousel/HomepageMissionsCarouselItem.vue +143 -0
  161. package/src/components/HomepageStats/HomepageStats.stories.js +155 -0
  162. package/src/components/HomepageStats/HomepageStats.vue +362 -0
  163. package/src/components/HomepageTeaserBlock/HomepageTeaserBlock.stories.js +90 -0
  164. package/src/components/HomepageTeaserBlock/HomepageTeaserBlock.vue +156 -0
  165. package/src/components/HomepageTeaserBlock/HomepageTeaserBlockCardImage.vue +58 -0
  166. package/src/components/Icons/Icon360.vue +29 -0
  167. package/src/components/Icons/IconArrow.vue +26 -0
  168. package/src/components/Icons/IconArrows.vue +43 -0
  169. package/src/components/Icons/IconAudio.vue +27 -0
  170. package/src/components/Icons/IconBook.vue +21 -0
  171. package/src/components/Icons/IconBookUser.vue +21 -0
  172. package/src/components/Icons/IconBriefcase.vue +21 -0
  173. package/src/components/Icons/IconCalendar.vue +25 -0
  174. package/src/components/Icons/IconCaret.vue +26 -0
  175. package/src/components/Icons/IconCheckbox.vue +26 -0
  176. package/src/components/Icons/IconCheckboxSelected.vue +35 -0
  177. package/src/components/Icons/IconClose.vue +27 -0
  178. package/src/components/Icons/IconCloseLightbox.vue +25 -0
  179. package/src/components/Icons/IconDownload.vue +31 -0
  180. package/src/components/Icons/IconDropdown.vue +25 -0
  181. package/src/components/Icons/IconEnvelope.vue +21 -0
  182. package/src/components/Icons/IconExpand.vue +28 -0
  183. package/src/components/Icons/IconExternal.vue +25 -0
  184. package/src/components/Icons/IconFilter.vue +25 -0
  185. package/src/components/Icons/IconForwardTen.vue +38 -0
  186. package/src/components/Icons/IconGrid.vue +25 -0
  187. package/src/components/Icons/IconHand.vue +21 -0
  188. package/src/components/Icons/IconInfo.vue +26 -0
  189. package/src/components/Icons/IconLink.vue +27 -0
  190. package/src/components/Icons/IconList.vue +25 -0
  191. package/src/components/Icons/IconLocation.vue +37 -0
  192. package/src/components/Icons/IconMagnifyingGlass.vue +21 -0
  193. package/src/components/Icons/IconMedal.vue +21 -0
  194. package/src/components/Icons/IconMenu.vue +27 -0
  195. package/src/components/Icons/IconMinus.vue +26 -0
  196. package/src/components/Icons/IconMute.vue +27 -0
  197. package/src/components/Icons/IconNext.vue +25 -0
  198. package/src/components/Icons/IconPause.vue +28 -0
  199. package/src/components/Icons/IconPlay.vue +28 -0
  200. package/src/components/Icons/IconPlus.vue +25 -0
  201. package/src/components/Icons/IconPrev.vue +25 -0
  202. package/src/components/Icons/IconRewindTen.vue +42 -0
  203. package/src/components/Icons/IconSearch.vue +25 -0
  204. package/src/components/Icons/IconShare.vue +30 -0
  205. package/src/components/Icons/IconSlideshow.vue +30 -0
  206. package/src/components/Icons/IconSocialEmail.vue +26 -0
  207. package/src/components/Icons/IconSocialFacebook.vue +26 -0
  208. package/src/components/Icons/IconSocialGoogleClassroom.vue +26 -0
  209. package/src/components/Icons/IconSocialInstagram.vue +35 -0
  210. package/src/components/Icons/IconSocialPinterest.vue +26 -0
  211. package/src/components/Icons/IconSocialReddit.vue +25 -0
  212. package/src/components/Icons/IconSocialTwitter.vue +25 -0
  213. package/src/components/Icons/IconSocialYoutube.vue +35 -0
  214. package/src/components/Icons/IconStop.vue +27 -0
  215. package/src/components/Icons/IconTime.vue +25 -0
  216. package/src/components/Icons/IconUniversity.vue +21 -0
  217. package/src/components/Icons/IconUser.vue +26 -0
  218. package/src/components/Icons/IconVolume.vue +27 -0
  219. package/src/components/Icons/Icons.stories.ts +440 -0
  220. package/src/components/ImageDetailContextImage/ImageDetailContextImage.vue +125 -0
  221. package/src/components/LayoutHelper/LayoutHelper.vue +38 -0
  222. package/src/components/LoadingTransition/LoadingTransition.vue +48 -0
  223. package/src/components/LogoCaltech/LogoCaltech.stories.js +39 -0
  224. package/src/components/LogoCaltech/LogoCaltech.vue +29 -0
  225. package/src/components/LogoTribrand/LogoTribrand.stories.js +76 -0
  226. package/src/components/LogoTribrand/LogoTribrand.vue +93 -0
  227. package/src/components/MissionDetailAbout/MissionDetailAbout.stories.js +70 -0
  228. package/src/components/MissionDetailAbout/MissionDetailAbout.vue +204 -0
  229. package/src/components/MissionDetailHero/MissionDetailHero.stories.js +303 -0
  230. package/src/components/MissionDetailHero/MissionDetailHero.vue +292 -0
  231. package/src/components/MissionDetailHighlights/MissionDetailHighlights.stories.js +278 -0
  232. package/src/components/MissionDetailHighlights/MissionDetailHighlights.vue +332 -0
  233. package/src/components/MissionDetailHighlights/MissionDetailHighlightsCarousel.vue +160 -0
  234. package/src/components/MissionDetailHighlights/MissionDetailHighlightsCarouselItem.vue +123 -0
  235. package/src/components/MissionDetailInlineImage/MissionDetailInlineImage.stories.js +43 -0
  236. package/src/components/MissionDetailInlineImage/MissionDetailInlineImage.vue +97 -0
  237. package/src/components/MissionDetailStats/DistanceStats.test.js +133 -0
  238. package/src/components/MissionDetailStats/DistanceStats.vue +250 -0
  239. package/src/components/MissionDetailStats/MissionDetailStats.stories.js +95 -0
  240. package/src/components/MissionDetailStats/MissionDetailStats.test.js +23 -0
  241. package/src/components/MissionDetailStats/MissionDetailStats.vue +187 -0
  242. package/src/components/MissionDetailStats/MissionDetailStatsMicro.vue +52 -0
  243. package/src/components/MissionDetailStats/MissionDetailStatsMini.vue +109 -0
  244. package/src/components/MissionDetailStreamfield/MissionDetailStreamfield.stories.js +55 -0
  245. package/src/components/MissionDetailStreamfield/MissionDetailStreamfield.vue +95 -0
  246. package/src/components/MixinAnimationCaret/MixinAnimationCaret.stories.ts +24 -0
  247. package/src/components/MixinAnimationCaret/MixinAnimationCaret.vue +81 -0
  248. package/src/components/MixinCarousel/MixinCarousel.docs.mdx +33 -0
  249. package/src/components/MixinCarousel/MixinCarousel.stories.js +53 -0
  250. package/src/components/MixinCarousel/MixinCarousel.vue +236 -0
  251. package/src/components/MixinDropdownToggle/MixinDropdownToggle.vue +53 -0
  252. package/src/components/MixinFancybox/MixinFancybox.vue +405 -0
  253. package/src/components/MixinFancybox/MixinFancyboxOpenButton.vue +35 -0
  254. package/src/components/MixinVideoBg/MixinVideoBg.stories.js +23 -0
  255. package/src/components/MixinVideoBg/MixinVideoBg.vue +39 -0
  256. package/src/components/NavDesktop/NavDesktop.stories.js +254 -0
  257. package/src/components/NavDesktop/NavDesktop.vue +355 -0
  258. package/src/components/NavDesktop/NavDesktopDropdown.vue +201 -0
  259. package/src/components/NavDesktop/NavDesktopDropdownContent.vue +87 -0
  260. package/src/components/NavDesktop/NavDesktopDropdownMore.vue +112 -0
  261. package/src/components/NavDesktop/NavDesktopTopHat.vue +56 -0
  262. package/src/components/NavHeading/NavHeading.stories.js +23 -0
  263. package/src/components/NavHeading/NavHeading.vue +40 -0
  264. package/src/components/NavHighlight/NavHighlight.stories.js +42 -0
  265. package/src/components/NavHighlight/NavHighlight.vue +67 -0
  266. package/src/components/NavLinkList/NavLinkList.stories.js +46 -0
  267. package/src/components/NavLinkList/NavLinkList.vue +66 -0
  268. package/src/components/NavLogoLinks/NavLogoLinks.stories.js +22 -0
  269. package/src/components/NavLogoLinks/NavLogoLinks.vue +57 -0
  270. package/src/components/NavMobile/NavMobile.stories.js +231 -0
  271. package/src/components/NavMobile/NavMobile.vue +280 -0
  272. package/src/components/NavMobile/NavMobileDropdown.vue +175 -0
  273. package/src/components/NavMobile/NavMobileLink.vue +69 -0
  274. package/src/components/NavMobile/NavMobileSecondaryDropdown.vue +124 -0
  275. package/src/components/NavSearchForm/NavSearchForm.stories.js +13 -0
  276. package/src/components/NavSearchForm/NavSearchForm.vue +102 -0
  277. package/src/components/NavSecondary/NavSecondary.stories.js +24 -0
  278. package/src/components/NavSecondary/NavSecondary.vue +191 -0
  279. package/src/components/NavSecondary/NavSecondaryDropdown.vue +181 -0
  280. package/src/components/NavSecondary/NavSecondaryDropdownContent.vue +140 -0
  281. package/src/components/NavSecondary/NavSecondaryLink.vue +62 -0
  282. package/src/components/NavSocial/NavSocial.stories.js +20 -0
  283. package/src/components/NavSocial/NavSocial.vue +97 -0
  284. package/src/components/NewsDetailMediaContact/NewsDetailMediaContact.stories.js +60 -0
  285. package/src/components/NewsDetailMediaContact/NewsDetailMediaContact.test.js +30 -0
  286. package/src/components/NewsDetailMediaContact/NewsDetailMediaContact.vue +73 -0
  287. package/src/components/ParallaxContainer/ParallaxContainer.stories.js +47 -0
  288. package/src/components/ParallaxContainer/ParallaxContainer.vue +76 -0
  289. package/src/components/ParallaxElement/ParallaxElement.vue +25 -0
  290. package/src/components/PastEventsCarousel/PastEventsCarousel.vue +86 -0
  291. package/src/components/PodcastEpisodeCard/PodcastEpisodeCard.vue +251 -0
  292. package/src/components/PodcastSeriesCarousel/PodcastSeriesCarousel.stories.js +235 -0
  293. package/src/components/PodcastSeriesCarousel/PodcastSeriesCarousel.vue +171 -0
  294. package/src/components/ProfileDetailSectionGroup/ProfileDetailSectionGroup.vue +84 -0
  295. package/src/components/RoboticsDetailStats/RoboticsDetailStats.stories.js +97 -0
  296. package/src/components/RoboticsDetailStats/RoboticsDetailStats.test.js +21 -0
  297. package/src/components/RoboticsDetailStats/RoboticsDetailStats.vue +217 -0
  298. package/src/components/RoboticsDetailStats/RoboticsDetailStatsMini.vue +182 -0
  299. package/src/components/SearchFilterGroup/SearchFilterGroup.stories.js +59 -0
  300. package/src/components/SearchFilterGroup/SearchFilterGroup.vue +221 -0
  301. package/src/components/SearchInput/SearchInput.stories.js +35 -0
  302. package/src/components/SearchInput/SearchInput.vue +93 -0
  303. package/src/components/SearchPagination/SearchPagination.stories.js +55 -0
  304. package/src/components/SearchPagination/SearchPagination.vue +173 -0
  305. package/src/components/SearchResultCard/SearchResultCard.stories.js +57 -0
  306. package/src/components/SearchResultCard/SearchResultCard.vue +282 -0
  307. package/src/components/SearchResultGridItem/SearchResultGridItem.stories.js +70 -0
  308. package/src/components/SearchResultGridItem/SearchResultGridItem.vue +140 -0
  309. package/src/components/SearchResultsList/SearchResultsList.vue +183 -0
  310. package/src/components/SearchSelectMenu/SearchSelectMenu.stories.js +25 -0
  311. package/src/components/SearchSelectMenu/SearchSelectMenu.vue +86 -0
  312. package/src/components/ShareButtons/ShareButtons.stories.js +16 -0
  313. package/src/components/ShareButtons/ShareButtons.vue +132 -0
  314. package/src/components/ShareButtonsEdu/ShareButtonsEdu.stories.js +14 -0
  315. package/src/components/ShareButtonsEdu/ShareButtonsEdu.vue +215 -0
  316. package/src/components/SkipLink/SkipLink.stories.js +9 -0
  317. package/src/components/SkipLink/SkipLink.vue +53 -0
  318. package/src/components/SwimlaneCTA/SwimlaneCTA.stories.mdx +77 -0
  319. package/src/components/SwimlaneCTA/SwimlaneCTA.vue +281 -0
  320. package/src/components/TheFooter/TheFooter.stories.js +602 -0
  321. package/src/components/TheFooter/TheFooter.vue +228 -0
  322. package/src/components/TheFooter/TheFooterSignUp.vue +61 -0
  323. package/src/components/ThumbnailCarousel/ThumbnailCarousel.stories.js +106 -0
  324. package/src/components/ThumbnailCarousel/ThumbnailCarousel.vue +76 -0
  325. package/src/components/TopicDetailMissionCarousel/TopicDetailMissionCarousel.stories.js +93 -0
  326. package/src/components/TopicDetailMissionCarousel/TopicDetailMissionCarousel.vue +68 -0
  327. package/src/components/TopicDetailMissionCarouselItem/TopicDetailMissionCarouselItem.stories.js +38 -0
  328. package/src/components/TopicDetailMissionCarouselItem/TopicDetailMissionCarouselItem.vue +104 -0
  329. package/src/components/TopicDetailMissionSpotlight/TopicDetailMissionSpotlight.stories.js +84 -0
  330. package/src/components/TopicDetailMissionSpotlight/TopicDetailMissionSpotlight.vue +112 -0
  331. package/src/components/TopicDetailMore/TopicDetailMore.stories.js +221 -0
  332. package/src/components/TopicDetailMore/TopicDetailMore.vue +124 -0
  333. package/src/components/TopicDetailMore/TopicDetailMoreVisibility.vue +51 -0
  334. package/src/components/TopicDetailMoreItem/TopicDetailMoreItem.stories.js +116 -0
  335. package/src/components/TopicDetailMoreItem/TopicDetailMoreItem.vue +130 -0
  336. package/src/components/TopicDetailStreamfield/TopicDetailStreamfield.stories.js +34 -0
  337. package/src/components/TopicDetailStreamfield/TopicDetailStreamfield.vue +98 -0
  338. package/src/components/YearTicker/YearTicker.stories.js +37 -0
  339. package/src/components/YearTicker/YearTicker.vue +132 -0
  340. package/src/docs/foundation/DynamicTokens.vue +106 -0
  341. package/src/docs/foundation/FontVariants.vue +80 -0
  342. package/src/docs/foundation/color.docs.mdx +112 -0
  343. package/src/docs/foundation/grid.docs.mdx +189 -0
  344. package/src/docs/foundation/grid.stories.js +263 -0
  345. package/src/docs/foundation/grid_layouthelpers.docs.mdx +78 -0
  346. package/src/docs/foundation/grid_layouthelpers.stories.js +53 -0
  347. package/src/docs/foundation/themes.docs.mdx +71 -0
  348. package/src/docs/foundation/themes.stories.js +63 -0
  349. package/src/docs/foundation/typography.docs.mdx +50 -0
  350. package/src/docs/foundation/typography.stories.js +119 -0
  351. package/src/interfaces.ts +129 -0
  352. package/src/main.ts +34 -0
  353. package/src/store/header.ts +40 -0
  354. package/src/store/theme.ts +27 -0
  355. package/src/templates/PageContent/PageContent.stories.js +92 -0
  356. package/src/templates/PageContent/PageContent.vue +140 -0
  357. package/src/templates/PageEventDetail/PageEventDetail.stories.js +104 -0
  358. package/src/templates/PageEventDetail/PageEventDetail.vue +358 -0
  359. package/src/templates/PageNewsDetail/PageNewsDetail.stories.js +158 -0
  360. package/src/templates/PageNewsDetail/PageNewsDetail.vue +242 -0
  361. package/src/templates/edu/PageEduNewsDetail.stories.js +64 -0
  362. package/src/templates/edu/PageEduNewsDetail.vue +155 -0
  363. package/src/templates/www/HomePage/HomePage.vue +30 -0
  364. package/src/utils/dayjs.js +32 -0
  365. package/src/utils/filters.js +33 -0
  366. package/src/utils/mixins.ts +353 -0
  367. package/src/vite-env.d.ts +1 -0
  368. package/tailwind.config.js +24 -0
  369. package/tsconfig.json +29 -0
  370. package/tsconfig.node.json +11 -0
  371. package/vite.config.ts +55 -0
@@ -0,0 +1,64 @@
1
+ import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs'
2
+ import BaseSwimlane from './BaseSwimlane.vue'
3
+
4
+ <Meta
5
+ title="Components/Base/BaseSwimlane"
6
+ component={BaseSwimlane}
7
+ parameters={{ viewMode: 'docs' }}
8
+ />
9
+
10
+ export const BaseSwimlaneData = {
11
+ words: [
12
+ 'Artists',
13
+ 'Communicators',
14
+ 'Designers',
15
+ 'Disruptors',
16
+ 'Dreamers',
17
+ 'Educators',
18
+ 'Engineers',
19
+ 'Innovators',
20
+ 'Inventors',
21
+ 'Makers',
22
+ 'Problem Solvers',
23
+ 'Roboticists',
24
+ 'Scientists',
25
+ 'Software Engineers',
26
+ 'Thinkers',
27
+ 'Visualizers'
28
+ ],
29
+ rows: 9,
30
+ scale: 2,
31
+ transition: 'ease-out',
32
+ transitionDuration: 1800,
33
+ transitionDelay: 800
34
+ }
35
+
36
+ export const BaseSwimlaneTemplate = (args) => ({
37
+ props: Object.keys(args),
38
+ components: { BaseSwimlane },
39
+ template: `<BaseSwimlane :words="words" :rows="rows" :scale="scale" :transition="transition" :transition-duration="transitionDuration" :transition-delay="transitionDelay"
40
+ ></BaseSwimlane>`
41
+ })
42
+
43
+ # Base Swimlane
44
+
45
+ ## Usage
46
+
47
+ The BaseSwimlane component is expected to contain an array of words to create a 'swimlane' effect as the text swims through.
48
+
49
+ <Canvas>
50
+ <Story
51
+ name="Default"
52
+ args={BaseSwimlaneData}
53
+ >
54
+ {BaseSwimlaneTemplate.bind({})}
55
+ </Story>
56
+ </Canvas>
57
+
58
+ ## Props
59
+
60
+ <ArgsTable for={BaseSwimlane} />
61
+
62
+ ## Example data
63
+
64
+ <code language="json">{JSON.stringify(BaseSwimlaneData, null, 2)}</code>
@@ -0,0 +1,204 @@
1
+ <template>
2
+ <div
3
+ :style="listParentStyle"
4
+ class="BaseSwimlane"
5
+ @mouseenter="toggleAnimation"
6
+ @mouseleave="toggleAnimation"
7
+ >
8
+ <ul :style="listStyle">
9
+ <li
10
+ v-for="(word, index) in list"
11
+ :key="index"
12
+ :style="itemStyle"
13
+ v-html="word"
14
+ />
15
+ </ul>
16
+ </div>
17
+ </template>
18
+
19
+ <script lang="ts">
20
+ // @ts-nocheck
21
+ import { defineComponent } from 'vue'
22
+
23
+ export default defineComponent({
24
+ name: 'BaseSwimlane',
25
+ props: {
26
+ words: {
27
+ type: Array,
28
+ default: () => {
29
+ return [
30
+ 'Artists',
31
+ 'Communicators',
32
+ 'Designers',
33
+ 'Disruptors',
34
+ 'Dreamers',
35
+ 'Educators',
36
+ 'Engineers',
37
+ 'Innovators',
38
+ 'Inventors',
39
+ 'Makers',
40
+ 'Problem Solvers',
41
+ 'Roboticists',
42
+ 'Scientists',
43
+ 'Software Engineers',
44
+ 'Thinkers',
45
+ 'Visualizers'
46
+ ]
47
+ }
48
+ },
49
+ rows: {
50
+ type: Number,
51
+ default: 1
52
+ },
53
+ scale: {
54
+ type: Number,
55
+ default: 1
56
+ },
57
+ transitionDuration: {
58
+ type: Number,
59
+ default: 1000
60
+ },
61
+ transitionDelay: {
62
+ type: Number,
63
+ default: 500
64
+ },
65
+ transition: {
66
+ type: String,
67
+ default: 'ease-out'
68
+ },
69
+ pauseOnHover: {
70
+ type: Boolean,
71
+ default: true
72
+ }
73
+ },
74
+ data() {
75
+ return {
76
+ list: [],
77
+ listTop: 0,
78
+ isPaused: false,
79
+ isMovingBackwards: false
80
+ }
81
+ },
82
+ computed: {
83
+ listCount() {
84
+ return this.list.length
85
+ },
86
+ fontSize() {
87
+ // scale from 16px font size
88
+ return 16 * this.scale
89
+ },
90
+ itemHeight() {
91
+ return this.fontSize * 1.5
92
+ },
93
+ listHeight() {
94
+ return this.itemHeight * this.listCount
95
+ },
96
+ listParentHeight() {
97
+ return this.itemHeight * this.rows
98
+ },
99
+ itemStyle() {
100
+ return `font-size: ${this.fontSize}px;
101
+ height: ${this.itemHeight}px;`
102
+ },
103
+ listStyle() {
104
+ return `height: ${this.listHeight}px;
105
+ transition-delay: ${this.transitionDelay}ms;
106
+ transition-duration: ${this.transitionDuration}ms;
107
+ transition-timing-function: ${this.transition};
108
+ will-change: transform;
109
+ transform: translateY(${this.listTop}px)`
110
+ },
111
+ listParentStyle() {
112
+ return `height: ${this.listParentHeight}px;`
113
+ }
114
+ },
115
+ // update word list
116
+ watch: {
117
+ words(val) {
118
+ this.list = val
119
+ }
120
+ },
121
+ // copy word list
122
+ created() {
123
+ this.list = this.words
124
+ },
125
+ // initiate animation
126
+ mounted() {
127
+ setTimeout(this.updateState, this.transitionDelay)
128
+ },
129
+ methods: {
130
+ updateState() {
131
+ // check if enough keywords or is not paused
132
+ if (this.listCount <= this.rows) return
133
+ if (this.isPaused) return
134
+ // update list state
135
+ if (this.isMovingBackwards) {
136
+ this.listTop += this.itemHeight
137
+ } else {
138
+ this.listTop -= this.itemHeight
139
+ }
140
+ // one way animation
141
+ if (this.listTop < this.rows * this.itemHeight - this.listHeight) {
142
+ this.listTop = 0
143
+ }
144
+ // set time out for next update
145
+ this.timeOutId = window.setTimeout(() => {
146
+ this.updateState()
147
+ }, this.transitionDuration + this.transitionDelay)
148
+ },
149
+ // pause/resume animaiton on hover
150
+ toggleAnimation() {
151
+ if (this.pauseOnHover) {
152
+ this.isPaused = !this.isPaused
153
+ if (this.isPaused) {
154
+ clearTimeout(this.timeOutId)
155
+ } else {
156
+ this.updateState()
157
+ }
158
+ }
159
+ }
160
+ }
161
+ })
162
+ </script>
163
+
164
+ <style lang="scss" scoped>
165
+ .BaseSwimlane {
166
+ @apply overflow-hidden;
167
+
168
+ -webkit-mask-image: -webkit-gradient(
169
+ linear,
170
+ left top,
171
+ left bottom,
172
+ color-stop(0, transparent),
173
+ color-stop(0.05, rgba(0, 0, 0, 0.35)),
174
+ color-stop(0.1, black),
175
+ color-stop(0.5, black),
176
+ color-stop(0.9, rgba(0, 0, 0, 0.15)),
177
+ color-stop(1, transparent)
178
+ );
179
+ @screen lg {
180
+ -webkit-mask-image: -webkit-gradient(
181
+ linear,
182
+ left top,
183
+ left bottom,
184
+ color-stop(0, transparent),
185
+ color-stop(0.1, rgba(0, 0, 0, 0.15)),
186
+ color-stop(0.35, black),
187
+ color-stop(0.65, black),
188
+ color-stop(0.9, rgba(0, 0, 0, 0.15)),
189
+ color-stop(1, transparent)
190
+ );
191
+ }
192
+
193
+ ul {
194
+ @apply list-none overflow-hidden transition-transform;
195
+
196
+ li {
197
+ @apply text-center p-0 m-0;
198
+ @screen lg {
199
+ @apply text-left font-medium;
200
+ }
201
+ }
202
+ }
203
+ }
204
+ </style>
@@ -0,0 +1,34 @@
1
+ import BaseTag from './BaseTag.vue'
2
+
3
+ export default {
4
+ title: 'Components/Base/BaseTag',
5
+ component: BaseTag,
6
+ argTypes: {
7
+ variant: {
8
+ type: { name: 'string', required: false },
9
+ description: 'The variant (color) of the tag',
10
+ control: { type: 'select' },
11
+ options: ['primary', 'secondary', 'action']
12
+ },
13
+ size: {
14
+ type: { name: 'string', required: false },
15
+ description: 'The size of the tag',
16
+ control: { type: 'select' },
17
+ options: ['sm', 'md', 'lg']
18
+ }
19
+ },
20
+ parameters: {
21
+ slots: {
22
+ default: 'Default slot'
23
+ }
24
+ }
25
+ }
26
+
27
+ // stories
28
+ export const PrimaryMedium = {
29
+ args: { size: 'md', variant: 'primary', default: 'Psyche Asteroid' }
30
+ }
31
+
32
+ export const SecondarySmall = {
33
+ args: { size: 'sm', variant: 'secondary', default: 'Do it yourself' }
34
+ }
@@ -0,0 +1,36 @@
1
+ <script setup lang="ts">
2
+ import type { Attributes } from './../../interfaces'
3
+
4
+ // using borders to vertically center wonky font face
5
+ const variantMap: Attributes = {
6
+ primary: 'bg-primary border-primary',
7
+ secondary: 'bg-secondary border-secondary',
8
+ action: 'bg-action border-action'
9
+ }
10
+
11
+ const sizeMap: Attributes = {
12
+ sm: 'text-xs uppercase border-t-2 py-1 px-2.5',
13
+ md: 'text-base capitalize border-t py-2 px-3',
14
+ lg: 'text-lg capitalize border-t py-2 px-3'
15
+ }
16
+
17
+ interface BaseTagProps {
18
+ variant?: string
19
+ size?: string
20
+ }
21
+
22
+ // define props
23
+ const props = withDefaults(defineProps<BaseTagProps>(), {
24
+ variant: 'primary',
25
+ size: 'md'
26
+ })
27
+ </script>
28
+ <template>
29
+ <p
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"
32
+ >
33
+ <slot />
34
+ <span class="sr-only">.</span>
35
+ </p>
36
+ </template>
@@ -0,0 +1,78 @@
1
+ import BaseTimer from './BaseTimer.vue'
2
+
3
+ export default {
4
+ title: 'Components/Base/BaseTimer',
5
+ component: BaseTimer
6
+ }
7
+
8
+ export const FullDateTime = {
9
+ args: {
10
+ targetDateTime: '2011-11-26 15:02:21+01:00',
11
+ selectedUnits: ['years', 'months', 'days', 'hours', 'minutes', 'seconds'],
12
+ inline: false,
13
+ countdown: false,
14
+ legendClass: 'text-gray-mid-dark'
15
+ }
16
+ }
17
+ export const DateOnly = {
18
+ args: {
19
+ targetDateTime: '2011-11-26 15:02:21+01:00',
20
+ selectedUnits: ['years', 'months', 'days'],
21
+ inline: false,
22
+ countdown: false
23
+ }
24
+ }
25
+
26
+ export const Mixed = {
27
+ args: {
28
+ targetDateTime: '2011-11-26 15:02:21+01:00',
29
+ selectedUnits: ['months', 'days', 'hours'],
30
+ inline: false,
31
+ countdown: false
32
+ }
33
+ }
34
+
35
+ export const Countdown = {
36
+ args: {
37
+ targetDateTime: new Date(new Date().getTime() + 999999999).toISOString(),
38
+ selectedUnits: ['years', 'months', 'days', 'hours', 'minutes', 'seconds'],
39
+ inline: false,
40
+ countdown: true
41
+ }
42
+ }
43
+
44
+ export const CountdownStop = {
45
+ args: {
46
+ targetDateTime: new Date(new Date().getTime() + 1000 * 10).toISOString(),
47
+ selectedUnits: ['years', 'months', 'days', 'hours', 'minutes', 'seconds'],
48
+ inline: false,
49
+ countdown: true
50
+ }
51
+ }
52
+
53
+ export const AutoUnits = {
54
+ args: {
55
+ targetDateTime: new Date(new Date().getTime() - 999999999).toISOString(),
56
+ selectedUnits: [],
57
+ inline: false,
58
+ countdown: false
59
+ }
60
+ }
61
+
62
+ export const AutoUnitsCountdown = {
63
+ args: {
64
+ targetDateTime: new Date(new Date().getTime() + 1000 * 10).toISOString(),
65
+ selectedUnits: [],
66
+ inline: false,
67
+ countdown: true
68
+ }
69
+ }
70
+
71
+ export const Inline = {
72
+ args: {
73
+ targetDateTime: '2011-11-26 15:02:21+01:00',
74
+ selectedUnits: ['years', 'months', 'days', 'hours', 'minutes', 'seconds'],
75
+ inline: true,
76
+ countdown: false
77
+ }
78
+ }
@@ -0,0 +1,15 @@
1
+ import { mount } from '@vue/test-utils'
2
+
3
+ import BaseTimer from './BaseTimer.vue'
4
+
5
+ describe('BaseTimer', () => {
6
+ test('does not display its values server-side', () => {
7
+ const wrapper = mount(BaseTimer, {
8
+ propsData: {
9
+ targetDateTime: '2011-11-26 15:02:21+01:00',
10
+ selectedUnits: ['years', 'months', 'days']
11
+ }
12
+ })
13
+ expect(wrapper.text().replace(/\s+/g, ' ')).toBe('Loading… Yrs : Mos : Days')
14
+ })
15
+ })
@@ -0,0 +1,270 @@
1
+ <template>
2
+ <component
3
+ :is="diff ? 'time' : 'div'"
4
+ class="BaseTimer whitespace-nowrap"
5
+ :datetime="diff ? diff.toISOString() : null"
6
+ :class="{ '-inline': inline }"
7
+ >
8
+ <span :hidden="!!diff">Loading…</span>
9
+ <span
10
+ class="transition-opacity duration-500 ease-in-out opacity-0"
11
+ :class="{ 'opacity-100': diff, 'flex justify-between': inline }"
12
+ >
13
+ <span
14
+ v-for="(unit, index) in selectedUnitsComputed"
15
+ :key="unit"
16
+ >
17
+ <!-- Add a break between the date and time components, for mobile version -->
18
+ <span
19
+ v-if="index !== 0"
20
+ class="text-stats-xl text-stats-separator"
21
+ :class="{
22
+ 'block invisible -mt-6 md:inline md:visible md:mt-0':
23
+ selectedUnitsComputed.length >= 4 && unit === 'hours'
24
+ }"
25
+ >&nbsp;:&nbsp;</span
26
+ >
27
+ <!-- Make the seconds unit left-aligned to avoid it shifting position constantly, -->
28
+ <!-- due to the lack of equal-width numerals. -->
29
+ <span
30
+ class="inline-block align-top"
31
+ :class="unit === 'seconds' ? 'text-left' : 'text-center'"
32
+ aria-hidden="true"
33
+ >
34
+ <span
35
+ class="text-stats-xl"
36
+ :class="{ 'text-seconds': unit === 'seconds' }"
37
+ >
38
+ <template v-if="countdown && isPast">00</template>
39
+ <template v-else>{{ unitValue(unit) }}</template>
40
+ </span>
41
+ <br v-if="!inline" />
42
+ <span class="unit text-body-xs uppercase">
43
+ {{ shortLabel(unit) }}
44
+ </span>
45
+ </span>
46
+ </span>
47
+ </span>
48
+ </component>
49
+ </template>
50
+ <script lang="ts">
51
+ import type { PropType } from 'vue'
52
+ import { defineComponent } from 'vue'
53
+ import dayjs, { Dayjs } from 'dayjs'
54
+ import duration, { type Duration } from 'dayjs/plugin/duration'
55
+ import minMax from 'dayjs/plugin/minMax'
56
+
57
+ dayjs.extend(duration)
58
+ dayjs.extend(minMax)
59
+
60
+ const calculateDuration = (start: Dayjs): Duration | undefined => {
61
+ // Use round seconds so the datetime string stays valid and can be read by screen readers.
62
+ // This also makes the timer run more reliably, as the difference is always 1 full second.
63
+ const now = dayjs().millisecond(0)
64
+ const max = dayjs.max(start, now)
65
+ const min = dayjs.min(start, now)
66
+ return max ? dayjs.duration(max.diff(min)) : undefined
67
+ }
68
+
69
+ // Based on https://day.js.org/docs/en/durations/creating#list-of-all-available-units.
70
+ export const timerUnits = {
71
+ years: { shortLabel: 'Yrs', longLabel: 'Years' },
72
+ months: { shortLabel: 'Mos', longLabel: 'Months' },
73
+ days: { shortLabel: 'Days', longLabel: 'Days' },
74
+ hours: { shortLabel: 'Hrs', longLabel: 'Hours' },
75
+ minutes: { shortLabel: 'Mins', longLabel: 'Minutes' },
76
+ seconds: { shortLabel: 'Secs', longLabel: 'Seconds' }
77
+ } as const
78
+ type UnitID = keyof typeof timerUnits
79
+
80
+ // Normally this should just be `number`, but due to our usage of `@types/node`
81
+ // we need to define this in a way that is compatible with both Node and browser code.
82
+ type Interval = ReturnType<typeof setInterval>
83
+
84
+ export default defineComponent({
85
+ name: 'BaseTimer',
86
+ props: {
87
+ targetDateTime: {
88
+ type: String,
89
+ required: true
90
+ },
91
+ // if blank, the first three significant units will show
92
+ selectedUnits: {
93
+ type: Array as PropType<UnitID[]>,
94
+ required: false,
95
+ validator: (val: UnitID[]): boolean => val.every((v) => Boolean(timerUnits[v]))
96
+ },
97
+ inline: {
98
+ type: Boolean,
99
+ required: false,
100
+ default: false
101
+ },
102
+ // if a countdown clock, then this will force it to stop at 0
103
+ countdown: {
104
+ type: Boolean,
105
+ required: false,
106
+ default: false
107
+ }
108
+ },
109
+ data(): {
110
+ diff: Duration | undefined
111
+ interval: Interval | undefined
112
+ } {
113
+ return {
114
+ diff: undefined,
115
+ interval: undefined
116
+ }
117
+ },
118
+ computed: {
119
+ selectedUnitsComputed(): UnitID[] {
120
+ if (!this.selectedUnits || this.selectedUnits.length === 0) {
121
+ const unitChoices = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
122
+ let significantUnits = [] as UnitID[]
123
+ unitChoices.forEach((e) =>
124
+ this.unitSignificant(e as UnitID) ? significantUnits.push(e as UnitID) : significantUnits
125
+ )
126
+ // if only three units (i.e. hours, minutes, seconds)
127
+ // then do not make significant units dynamic
128
+ // (we always want a minimum of three to show)
129
+ if (significantUnits.length <= 3) {
130
+ return ['hours', 'minutes', 'seconds']
131
+ } else {
132
+ significantUnits = significantUnits.slice(0, 3)
133
+ }
134
+
135
+ return significantUnits
136
+ }
137
+ return this.selectedUnits
138
+ },
139
+ isPast(): boolean {
140
+ if (this.targetDateTime) {
141
+ const now = dayjs(new Date())
142
+ const start = dayjs(new Date(this.targetDateTime.replace(/\s+/g, 'T'))).millisecond(0)
143
+ if (start.isBefore(now)) {
144
+ return true
145
+ }
146
+ }
147
+ return false
148
+ }
149
+ },
150
+ mounted(): void {
151
+ // Convert ISO8601 RFC 3339 datetime formats into a stricter format supported by Safari.
152
+ const start = dayjs(new Date(this.targetDateTime.replace(/\s+/g, 'T'))).millisecond(0)
153
+
154
+ this.diff = calculateDuration(start)
155
+
156
+ // Only make the timer live-update if there are units that are going to show live changes.
157
+ const shouldUpdate =
158
+ this.selectedUnitsComputed.includes('seconds') ||
159
+ this.selectedUnitsComputed.includes('minutes')
160
+ if (shouldUpdate) {
161
+ // Imprecise timer, but keeps performance impact very low.
162
+ this.interval = setInterval(() => {
163
+ this.diff = calculateDuration(start)
164
+
165
+ const countdownTimer = this.diff?.as('seconds') === 0
166
+ if (countdownTimer) {
167
+ clearInterval(this.interval as Interval)
168
+ }
169
+ }, 1000)
170
+ }
171
+ },
172
+ beforeUnmount(): void {
173
+ clearInterval(this.interval as Interval)
174
+ },
175
+ methods: {
176
+ shortLabel(unit: UnitID) {
177
+ return timerUnits[unit]?.shortLabel || unit
178
+ },
179
+ longLabel(unit: UnitID) {
180
+ return timerUnits[unit]?.longLabel || unit
181
+ },
182
+ unitSignificant(unit: UnitID): boolean {
183
+ if (this.diff === null) {
184
+ return false
185
+ }
186
+ const value = this.diff?.get(unit)
187
+
188
+ if ((value && value > 0) || this.checkOtherUnits(unit)) {
189
+ return true
190
+ }
191
+ return false
192
+ },
193
+ // TODO: make this more efficient
194
+ checkOtherUnits(unit: UnitID): boolean {
195
+ // necessary to check if higher units have a value, otherwise 0 values will not display when they should
196
+ if (this.diff) {
197
+ if (unit === 'seconds') {
198
+ if (
199
+ this.diff.get('minutes') > 0 ||
200
+ this.diff.get('hours') > 0 ||
201
+ this.diff.get('days') > 0 ||
202
+ this.diff.get('months') > 0 ||
203
+ this.diff.get('years') > 0
204
+ ) {
205
+ return true
206
+ }
207
+ } else if (unit === 'minutes') {
208
+ if (
209
+ this.diff.get('hours') > 0 ||
210
+ this.diff.get('days') > 0 ||
211
+ this.diff.get('months') > 0 ||
212
+ this.diff.get('years') > 0
213
+ ) {
214
+ return true
215
+ }
216
+ } else if (unit === 'hours') {
217
+ if (
218
+ this.diff.get('days') > 0 ||
219
+ this.diff.get('months') > 0 ||
220
+ this.diff.get('years') > 0
221
+ ) {
222
+ return true
223
+ }
224
+ } else if (unit === 'days') {
225
+ if (this.diff.get('months') > 0 || this.diff.get('years') > 0) {
226
+ return true
227
+ }
228
+ } else if (unit === 'months') {
229
+ if (this.diff.get('years') > 0) {
230
+ return true
231
+ }
232
+ }
233
+ }
234
+ return false
235
+ },
236
+ unitValue(unit: UnitID) {
237
+ if (this.diff === null) {
238
+ return ''
239
+ }
240
+
241
+ const value = this.diff?.get(unit)
242
+
243
+ // Pad a number with a leading zero.
244
+ return value?.toString().padStart(2, '0')
245
+ }
246
+ }
247
+ })
248
+ </script>
249
+ <style lang="scss">
250
+ .BaseTimer {
251
+ .unit {
252
+ // Make the units dimmer than the numbers, regardless of which color it’s displayed with.
253
+ --text-opacity: 0.84;
254
+ }
255
+
256
+ &.-inline {
257
+ .text-stats-separator {
258
+ @apply hidden;
259
+ }
260
+
261
+ .text-seconds {
262
+ width: 2ch;
263
+ }
264
+
265
+ > span span {
266
+ @apply inline-block;
267
+ }
268
+ }
269
+ }
270
+ </style>