@icij/murmur-next 4.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 (296) hide show
  1. package/.github/workflows/deploy-github-pages.yaml +50 -0
  2. package/.storybook/app.scss +14 -0
  3. package/.storybook/doc_variables.scss +20 -0
  4. package/.storybook/main.ts +35 -0
  5. package/.storybook/preview-head.html +2 -0
  6. package/.storybook/preview.ts +32 -0
  7. package/README.md +71 -0
  8. package/deploy.js +15 -0
  9. package/docs/components/ApiTable.vue +171 -0
  10. package/docs/components/App.vue +146 -0
  11. package/docs/components/CollapsibleBlock.vue +122 -0
  12. package/docs/components/DocsHeader.vue +68 -0
  13. package/docs/components/DocsMenu.vue +201 -0
  14. package/docs/components/DocsMenuSection.vue +109 -0
  15. package/docs/components/EditLink.vue +49 -0
  16. package/docs/components/OutboundLink.vue +13 -0
  17. package/docs/components/PalettePresenter.vue +96 -0
  18. package/docs/components/RepositoryLink.vue +28 -0
  19. package/docs/components/SampleCard.vue +119 -0
  20. package/docs/main.js +42 -0
  21. package/docs/pages/components/accordion/doc.md +96 -0
  22. package/docs/pages/components/active-text-truncate/doc.md +44 -0
  23. package/docs/pages/components/advanced-link-form/doc.md +105 -0
  24. package/docs/pages/components/brand/doc.md +30 -0
  25. package/docs/pages/components/brand-expansion/doc.md +70 -0
  26. package/docs/pages/components/confirm-button/doc.md +91 -0
  27. package/docs/pages/components/content-placeholder/doc.md +16 -0
  28. package/docs/pages/components/custom-pagination/doc.md +61 -0
  29. package/docs/pages/components/digits-input/doc.md +28 -0
  30. package/docs/pages/components/donate-form/doc.md +20 -0
  31. package/docs/pages/components/embed-form/doc.md +22 -0
  32. package/docs/pages/components/embeddable-footer/doc.md +60 -0
  33. package/docs/pages/components/follow-us-popover/doc.md +5 -0
  34. package/docs/pages/components/generic-footer/doc.md +21 -0
  35. package/docs/pages/components/generic-header/doc.md +24 -0
  36. package/docs/pages/components/haptic-copy/doc.md +27 -0
  37. package/docs/pages/components/imddb-header/doc.md +23 -0
  38. package/docs/pages/components/ordinal-legend/doc.md +44 -0
  39. package/docs/pages/components/range-picker/doc.md +86 -0
  40. package/docs/pages/components/responsive-iframe/doc.md +13 -0
  41. package/docs/pages/components/scale-legend/doc.md +65 -0
  42. package/docs/pages/components/secret-input/doc.md +12 -0
  43. package/docs/pages/components/selectable-dropdown/doc.md +156 -0
  44. package/docs/pages/components/sharing-options/doc.md +13 -0
  45. package/docs/pages/components/sharing-options-link/doc.md +36 -0
  46. package/docs/pages/components/sign-up-form/doc.md +13 -0
  47. package/docs/pages/components/slide-up-down/doc.md +28 -0
  48. package/docs/pages/components/textured-deck/doc.md +78 -0
  49. package/docs/pages/components/tiny-pagination/doc.md +92 -0
  50. package/docs/pages/datavisualisation/bars/doc.md +110 -0
  51. package/docs/pages/datavisualisation/columns/doc.md +165 -0
  52. package/docs/pages/datavisualisation/lines/doc.md +139 -0
  53. package/docs/pages/datavisualisation/stacked-bar/doc.md +160 -0
  54. package/docs/pages/datavisualisation/stacked-column/doc.md +191 -0
  55. package/docs/pages/getting-started/about-icij/doc.md +13 -0
  56. package/docs/pages/getting-started/custom-bootstrap/doc.md +36 -0
  57. package/docs/pages/getting-started/installation-guide/doc.md +59 -0
  58. package/docs/pages/getting-started/internationalization/doc.md +74 -0
  59. package/docs/pages/maps/choropleth-map/doc.md +420 -0
  60. package/docs/pages/maps/choropleth-map-annotation/doc.md +373 -0
  61. package/docs/pages/maps/symbol-map/doc.md +203 -0
  62. package/docs/pages/structure/breakpoints/doc.md +3 -0
  63. package/docs/pages/structure/grid/doc.md +3 -0
  64. package/docs/pages/utilities/assets/doc.md +138 -0
  65. package/docs/pages/utilities/config/doc.md +52 -0
  66. package/docs/pages/utilities/iframes/doc.md +3 -0
  67. package/docs/pages/visual/colors/doc.md +31 -0
  68. package/docs/pages/visual/iconography/doc.md +56 -0
  69. package/docs/pages/visual/states/doc.md +77 -0
  70. package/docs/pages/visual/themes/doc.md +3 -0
  71. package/docs/pages/visual/typography/doc.md +71 -0
  72. package/docs/routes.js +25 -0
  73. package/docs/store/index.js +21 -0
  74. package/docs/styles/app.scss +36 -0
  75. package/docs/styles/variables.scss +20 -0
  76. package/lib/assets/images/icij-full-white.svg +6 -0
  77. package/lib/assets/images/icij-full.svg +6 -0
  78. package/lib/assets/images/icij.png +0 -0
  79. package/lib/assets/images/icij.svg +46 -0
  80. package/lib/assets/images/icij@2x.png +0 -0
  81. package/lib/assets/images/murmur-dark.png +0 -0
  82. package/lib/assets/images/murmur-dark.svg +79 -0
  83. package/lib/assets/images/murmur-white.png +0 -0
  84. package/lib/assets/images/murmur-white.svg +68 -0
  85. package/lib/components/AccordionStep.vue +128 -0
  86. package/lib/components/AccordionWrapper.vue +138 -0
  87. package/lib/components/ActiveTextTruncate.vue +258 -0
  88. package/lib/components/AdvancedLinkForm.vue +273 -0
  89. package/lib/components/Brand.vue +150 -0
  90. package/lib/components/BrandExpansion.vue +237 -0
  91. package/lib/components/ConfirmButton.vue +204 -0
  92. package/lib/components/ContentPlaceholder.vue +100 -0
  93. package/lib/components/CustomPagination.vue +225 -0
  94. package/lib/components/DigitsInput.vue +180 -0
  95. package/lib/components/DonateForm.vue +367 -0
  96. package/lib/components/EmbedForm.vue +173 -0
  97. package/lib/components/EmbeddableFooter.vue +201 -0
  98. package/lib/components/Fa.js +3 -0
  99. package/lib/components/FollowUsPopover.vue +117 -0
  100. package/lib/components/GenericFooter.vue +218 -0
  101. package/lib/components/GenericHeader.vue +259 -0
  102. package/lib/components/HapticCopy.vue +256 -0
  103. package/lib/components/ImddbHeader.vue +336 -0
  104. package/lib/components/OrdinalLegend.vue +164 -0
  105. package/lib/components/RangePicker.vue +430 -0
  106. package/lib/components/ResponsiveIframe.vue +48 -0
  107. package/lib/components/ScaleLegend.vue +230 -0
  108. package/lib/components/SecretInput.vue +132 -0
  109. package/lib/components/SelectableDropdown.vue +368 -0
  110. package/lib/components/SharingOptions.vue +230 -0
  111. package/lib/components/SharingOptionsLink.vue +259 -0
  112. package/lib/components/SignUpForm.vue +181 -0
  113. package/lib/components/SlideUpDown.vue +131 -0
  114. package/lib/components/TexturedDeck.vue +101 -0
  115. package/lib/components/TinyPagination.vue +268 -0
  116. package/lib/components/index.js +31 -0
  117. package/lib/composables/chart.ts +182 -0
  118. package/lib/composables/resizeObserver.ts +37 -0
  119. package/lib/composables/sendEmail.ts +50 -0
  120. package/lib/config.default.ts +33 -0
  121. package/lib/config.ts +70 -0
  122. package/lib/d3-geo-projection.d.ts +1 -0
  123. package/lib/datavisualisations/BarChart.vue +275 -0
  124. package/lib/datavisualisations/ColumnChart.vue +527 -0
  125. package/lib/datavisualisations/LineChart.vue +274 -0
  126. package/lib/datavisualisations/StackedBarChart.vue +614 -0
  127. package/lib/datavisualisations/StackedColumnChart.vue +640 -0
  128. package/lib/datavisualisations/index.js +5 -0
  129. package/lib/enums.ts +25 -0
  130. package/lib/i18n.ts +16 -0
  131. package/lib/keys.ts +2 -0
  132. package/lib/locales/en.json +140 -0
  133. package/lib/locales/fr.json +117 -0
  134. package/lib/locales/locales/en.json +140 -0
  135. package/lib/locales/locales/fr.json +117 -0
  136. package/lib/main.ts +87 -0
  137. package/lib/maps/ChoroplethMap.vue +825 -0
  138. package/lib/maps/ChoroplethMapAnnotation.vue +336 -0
  139. package/lib/maps/SymbolMap.vue +628 -0
  140. package/lib/maps/index.js +3 -0
  141. package/lib/querystring-es3.d.ts +1 -0
  142. package/lib/shims-bootstrap-vue.d.ts +5 -0
  143. package/lib/shims-tsx.d.ts +11 -0
  144. package/lib/shims-vue.d.ts +14 -0
  145. package/lib/styles/functions.scss +20 -0
  146. package/lib/styles/lib.scss +19 -0
  147. package/lib/styles/mixins.scss +37 -0
  148. package/lib/styles/utilities.scss +18 -0
  149. package/lib/styles/variables.scss +94 -0
  150. package/lib/styles/variables_dark.scss +1 -0
  151. package/lib/types.ts +46 -0
  152. package/lib/utils/animation.ts +24 -0
  153. package/lib/utils/assets.ts +46 -0
  154. package/lib/utils/clipboard.ts +41 -0
  155. package/lib/utils/iframe-resizer.ts +49 -0
  156. package/lib/utils/placeholder.ts +66 -0
  157. package/lib/utils/placeholderTypes.ts +21 -0
  158. package/lib/utils/strings.ts +8 -0
  159. package/loaders/highlight-loader.js +13 -0
  160. package/loaders/markdown-loader.js +91 -0
  161. package/loaders/metadata-loader.js +18 -0
  162. package/loaders/sass-extract-loader.js +14 -0
  163. package/loaders/vue-docgen-loader.js +14 -0
  164. package/package.json +96 -0
  165. package/plugins/MdPluginTypes.ts +10 -0
  166. package/plugins/docs.ts +50 -0
  167. package/plugins/front-matter.ts +36 -0
  168. package/plugins/highlight.ts +27 -0
  169. package/plugins/markdown-it/api-table.ts +25 -0
  170. package/plugins/markdown-it/sample-card.ts +31 -0
  171. package/plugins/plugin-delete.ts +47 -0
  172. package/plugins/plugin-docgen.ts +23 -0
  173. package/plugins/sass-vars.ts +25 -0
  174. package/plugins/vue-docgen.ts +29 -0
  175. package/public/android-chrome-192x192.png +0 -0
  176. package/public/android-chrome-512x512.png +0 -0
  177. package/public/apple-touch-icon.png +0 -0
  178. package/public/assets/img/arrow-bottom.svg +3 -0
  179. package/public/assets/img/texture-brick-black.jpg +0 -0
  180. package/public/assets/img/texture-brick.jpg +0 -0
  181. package/public/assets/img/texture-carbon-black.jpg +0 -0
  182. package/public/assets/img/texture-carbon.jpg +0 -0
  183. package/public/assets/img/texture-crack-black.jpg +0 -0
  184. package/public/assets/img/texture-crack.jpg +0 -0
  185. package/public/assets/img/texture-rock-black.jpg +0 -0
  186. package/public/assets/img/texture-rock.jpg +0 -0
  187. package/public/assets/img/texture-sand-black.jpg +0 -0
  188. package/public/assets/img/texture-sand.jpg +0 -0
  189. package/public/assets/img/texture-silk-black.jpg +0 -0
  190. package/public/assets/img/texture-silk.jpg +0 -0
  191. package/public/assets/topojson/france-departments.json +1 -0
  192. package/public/assets/topojson/paris-arrondissements.json +1 -0
  193. package/public/assets/topojson/world-countries-sans-antarctica.json +1 -0
  194. package/public/favicon-16x16.png +0 -0
  195. package/public/favicon-32x32.png +0 -0
  196. package/public/favicon.ico +0 -0
  197. package/public/site.webmanifest +1 -0
  198. package/stories/assets/code-brackets.svg +1 -0
  199. package/stories/assets/colors.svg +1 -0
  200. package/stories/assets/comments.svg +1 -0
  201. package/stories/assets/direction.svg +1 -0
  202. package/stories/assets/flow.svg +1 -0
  203. package/stories/assets/plugin.svg +1 -0
  204. package/stories/assets/repo.svg +1 -0
  205. package/stories/assets/stackalt.svg +1 -0
  206. package/stories/getting-started/about-icij.mdx +14 -0
  207. package/stories/getting-started/custom-bootstrap.mdx +23 -0
  208. package/stories/getting-started/installation-guide.mdx +62 -0
  209. package/stories/getting-started/internationalization.mdx +63 -0
  210. package/stories/murmur/components/AccordionStep.stories.ts +33 -0
  211. package/stories/murmur/components/AccordionWrapper.stories.ts +69 -0
  212. package/stories/murmur/components/ActiveTextTruncate.stories.ts +32 -0
  213. package/stories/murmur/components/AdvancedLinkForm.stories.ts +77 -0
  214. package/stories/murmur/components/Brand.stories.ts +30 -0
  215. package/stories/murmur/components/BrandExpansion.stories.ts +41 -0
  216. package/stories/murmur/components/ConfirmButton.stories.ts +40 -0
  217. package/stories/murmur/components/ContentPlaceholder.stories.ts +41 -0
  218. package/stories/murmur/components/CustomPagination.stories.ts +42 -0
  219. package/stories/murmur/components/DigitsInput.stories.ts +29 -0
  220. package/stories/murmur/components/DonateForm.stories.ts +29 -0
  221. package/stories/murmur/components/EmbedForm.stories.ts +35 -0
  222. package/stories/murmur/components/EmbeddableFooter.stories.ts +59 -0
  223. package/stories/murmur/components/FollowUsPopover.stories.ts +24 -0
  224. package/stories/murmur/components/GenericFooter.stories.ts +27 -0
  225. package/stories/murmur/components/GenericHeader.stories.ts +27 -0
  226. package/stories/murmur/components/HapticCopy.stories.ts +40 -0
  227. package/stories/murmur/components/ImddbHeader.stories.ts +27 -0
  228. package/stories/murmur/components/OrdinalLegend.stories.ts +49 -0
  229. package/stories/murmur/components/RangePicker.stories.ts +98 -0
  230. package/stories/murmur/components/ResponsiveIframe.stories.ts +24 -0
  231. package/stories/murmur/components/ScaleLegend.stories.ts +65 -0
  232. package/stories/murmur/components/SecretInput.stories.ts +60 -0
  233. package/stories/murmur/components/SelectableDropdown.stories.ts +143 -0
  234. package/stories/murmur/components/SharingOptions.stories.ts +32 -0
  235. package/stories/murmur/components/SharingOptionsLink.stories.ts +53 -0
  236. package/stories/murmur/components/SignUpForm.stories.ts +51 -0
  237. package/stories/murmur/components/SlideUpDown.stories.ts +32 -0
  238. package/stories/murmur/components/TexturedDeck.stories.ts +83 -0
  239. package/stories/murmur/components/TinyPagination.stories.ts +65 -0
  240. package/stories/murmur/datavisualisations/BarChart.stories.ts +54 -0
  241. package/stories/murmur/datavisualisations/ColumnChart.stories.ts +88 -0
  242. package/stories/murmur/datavisualisations/LineChart.stories.ts +139 -0
  243. package/stories/murmur/datavisualisations/StackedBarChart.stories.ts +199 -0
  244. package/stories/murmur/datavisualisations/StackedColumnChart.stories.ts +136 -0
  245. package/stories/murmur/decorators.ts +108 -0
  246. package/stories/murmur/maps/ChoroplethMap.stories.ts +440 -0
  247. package/stories/murmur/maps/ChoroplethMapAnnotation.stories.ts +26 -0
  248. package/stories/murmur/maps/SymbolMap.stories.ts +24 -0
  249. package/stories/murmur/utils.ts +7 -0
  250. package/tests/unit/components/AccordionStep.spec.ts +157 -0
  251. package/tests/unit/components/AccordionWrapper.spec.ts +57 -0
  252. package/tests/unit/components/ActiveTextTruncate.spec.js +30 -0
  253. package/tests/unit/components/AdvancedLinkForm.spec.js +124 -0
  254. package/tests/unit/components/Brand.spec.js +50 -0
  255. package/tests/unit/components/ContentPlaceholder.spec.js +29 -0
  256. package/tests/unit/components/CustomPagination.spec.js +72 -0
  257. package/tests/unit/components/DigitsInput.spec.ts +157 -0
  258. package/tests/unit/components/DonateForm.spec.js +149 -0
  259. package/tests/unit/components/EmbedForm.spec.js +108 -0
  260. package/tests/unit/components/EmbeddableFooter.spec.js +11 -0
  261. package/tests/unit/components/Fa.spec.js +18 -0
  262. package/tests/unit/components/FollowUsPopover.spec.js +29 -0
  263. package/tests/unit/components/GenericFooter.spec.js +29 -0
  264. package/tests/unit/components/GenericHeader.spec.js +104 -0
  265. package/tests/unit/components/HapticCopy.spec.js +123 -0
  266. package/tests/unit/components/ImddbHeader.spec.js +96 -0
  267. package/tests/unit/components/OrdinalLegend.spec.js +120 -0
  268. package/tests/unit/components/RangePicker.spec.ts +87 -0
  269. package/tests/unit/components/ResponsiveIframe.spec.js +20 -0
  270. package/tests/unit/components/ScaleLegend.spec.js +139 -0
  271. package/tests/unit/components/SecretInput.spec.js +81 -0
  272. package/tests/unit/components/SelectableDropdown.spec.js +160 -0
  273. package/tests/unit/components/SharingOptions.spec.js +125 -0
  274. package/tests/unit/components/SharingOptionsLink.spec.js +184 -0
  275. package/tests/unit/components/SignUpForm.spec.js +145 -0
  276. package/tests/unit/components/SlideUpDown.spec.js +59 -0
  277. package/tests/unit/components/TinyPagination.spec.js +46 -0
  278. package/tests/unit/config.spec.js +136 -0
  279. package/tests/unit/datavisualisations/BarChart.spec.js +63 -0
  280. package/tests/unit/datavisualisations/ColumnChart.spec.js +344 -0
  281. package/tests/unit/datavisualisations/LineChart.spec.js +155 -0
  282. package/tests/unit/datavisualisations/StackedBarChart.spec.js +294 -0
  283. package/tests/unit/datavisualisations/StackedColumnChart.spec.js +443 -0
  284. package/tests/unit/i18n.spec.ts +19 -0
  285. package/tests/unit/main.spec.js +82 -0
  286. package/tests/unit/maps/ChoroplethMap.spec.js +214 -0
  287. package/tests/unit/maps/ChoroplethMapAnnotation.spec.ts +186 -0
  288. package/tests/unit/maps/SymbolMap.spec.js +92 -0
  289. package/tests/unit/require.spec.js +22 -0
  290. package/tests/unit/setup.js +13 -0
  291. package/tests/unit/utils/assets.spec.js +61 -0
  292. package/tests/unit/utils/clipboard.spec.js +18 -0
  293. package/tests/unit/utils/iframe-resizer.spec.js +71 -0
  294. package/tsconfig.json +35 -0
  295. package/vite.config.ts +79 -0
  296. package/vitest.config.ts +19 -0
@@ -0,0 +1,131 @@
1
+ <script lang="ts">
2
+ import { defineComponent } from 'vue'
3
+ import type { CSSProperties } from 'vue'
4
+
5
+ type StyleTransition = Pick<CSSProperties, 'overflow' | 'transition-property' | 'transition-duration' | 'height'>
6
+ const STATE = {
7
+ PRE: 'pre',
8
+ ACTIVE: 'active',
9
+ POST: 'post'
10
+ }
11
+ interface SlideUpDownData {
12
+ state: string
13
+ mounted: boolean
14
+ scrollHeight: number
15
+ }
16
+ /**
17
+ * SlideUpDown
18
+ */
19
+ export default defineComponent({
20
+ name: 'SlideUpDown',
21
+ props: {
22
+ /**
23
+ * Toggler property. Set to <em>false</em> to hide the component.
24
+ */
25
+ active: {
26
+ type: Boolean,
27
+ default: false
28
+ },
29
+ /**
30
+ * Duration of the animation.
31
+ */
32
+ duration: {
33
+ type: Number,
34
+ default: 200
35
+ },
36
+ /**
37
+ * HTML tag to render this component to.
38
+ */
39
+ tag: {
40
+ type: String,
41
+ default: 'div'
42
+ }
43
+ },
44
+ data(): SlideUpDownData {
45
+ return {
46
+ state: STATE.POST,
47
+ mounted: false,
48
+ scrollHeight: 0
49
+ }
50
+ },
51
+ computed: {
52
+ stylePreTransition(): StyleTransition {
53
+ return {
54
+ overflow: 'hidden',
55
+ 'transition-property': 'height',
56
+ 'transition-duration': `${this.duration}ms`,
57
+ height: this.mounted ? `${this.containerScrollHeight}px` : 0
58
+ }
59
+ },
60
+ styleActiveTransition(): StyleTransition {
61
+ return {
62
+ overflow: 'hidden',
63
+ 'transition-property': 'height',
64
+ 'transition-duration': `${this.duration}ms`,
65
+ height: this.mounted ? `${this.activeHeight}px` : 'auto'
66
+ }
67
+ },
68
+ stylePostTransition(): StyleTransition {
69
+ // Reset style when the element is active
70
+ return this.active ? {} : this.styleActiveTransition
71
+ },
72
+ style(): StyleTransition {
73
+ switch (this.state) {
74
+ case STATE.PRE:
75
+ return this.stylePreTransition
76
+ case STATE.ACTIVE:
77
+ return this.styleActiveTransition
78
+ default:
79
+ return this.stylePostTransition
80
+ }
81
+ },
82
+ activeHeight(): number {
83
+ return this.active ? this.containerScrollHeight : 0
84
+ },
85
+ containerScrollHeight(): number {
86
+ return this.$container?.scrollHeight ?? 0
87
+ },
88
+ $container(): HTMLElement | undefined {
89
+ return this.$refs.container as HTMLElement | undefined
90
+ }
91
+ },
92
+ watch: {
93
+ active(): Promise<void> {
94
+ return this.triggerSlide()
95
+ }
96
+ },
97
+ async mounted() {
98
+ await this.deferredNextTick()
99
+ this.mounted = true
100
+ await this.cleanLayout(null)
101
+ this.$container?.addEventListener('transitionend', (e) => this.cleanLayout(e))
102
+ },
103
+ methods: {
104
+ async triggerSlide(): Promise<void> {
105
+ this.state = STATE.PRE
106
+ this.scrollHeight = this.containerScrollHeight
107
+ // Deferred next tick to let the component render once
108
+ await this.deferredNextTick()
109
+ this.state = STATE.ACTIVE
110
+ },
111
+ cleanLayout(e: Event | null) {
112
+ // This method can be triggered by animated child elements in
113
+ // which case, we should do anything
114
+ if (!e || e.target === this.$container) {
115
+ this.state = STATE.POST
116
+ return this.deferredNextTick()
117
+ }
118
+ },
119
+ async deferredNextTick() {
120
+ await new Promise((resolve) => setTimeout(resolve, 0))
121
+ await this.$nextTick()
122
+ }
123
+ }
124
+ })
125
+ </script>
126
+
127
+ <template>
128
+ <component :is="tag" ref="container" :style="style">
129
+ <slot />
130
+ </component>
131
+ </template>
@@ -0,0 +1,101 @@
1
+ <script lang="ts">
2
+ import { clamp } from 'lodash'
3
+ import {computed, defineComponent, PropType} from 'vue'
4
+
5
+ import { DeckTexture } from '@/enums'
6
+ import config from '@/config'
7
+
8
+ type TexturedDeckValue = DeckTexture | number
9
+
10
+ export default defineComponent({
11
+ name: 'TexturedDeck',
12
+ props: {
13
+ /**
14
+ * Name of the texture file ('silk', 'brick', 'rock', 'sand', 'crack', 'carbon')
15
+ */
16
+ modelValue: {
17
+ type: String as PropType<TexturedDeckValue>,
18
+ default: DeckTexture.Brick
19
+ },
20
+ /**
21
+ * CSS background-size property (cover, contain, auto, 50%, 50% auto, ...)
22
+ */
23
+ size: {
24
+ type: String,
25
+ default: 'cover'
26
+ },
27
+ /**
28
+ * Tag/Component to use as root tag.
29
+ */
30
+ tag: {
31
+ type: [String, Object],
32
+ default: 'div'
33
+ },
34
+ /**
35
+ * Either or note we should use the black version of the texture
36
+ */
37
+ black: {
38
+ type: Boolean,
39
+ default:false
40
+ },
41
+ /**
42
+ * Host where to find the textures (without tailing slash)
43
+ */
44
+ backgroundBaseUrl: {
45
+ type: String,
46
+ default: () => config.get('textured-deck.background-base-url', window.location.origin)
47
+ }
48
+ },
49
+ setup(props, {attrs}) {
50
+ const names = computed((): DeckTexture[] =>{
51
+ return Object.values(DeckTexture)
52
+ })
53
+ const textureIndex = computed((): number =>{
54
+ if (typeof props.modelValue !== 'number') {
55
+ return clamp(names.value.indexOf(props.modelValue), 0, names.value.length - 1)
56
+ }
57
+ return props.modelValue
58
+ })
59
+ const textureName = computed((): string =>{
60
+ return names.value[textureIndex.value]
61
+ })
62
+ const filename = computed((): string =>{
63
+ if (props.black) {
64
+ return `texture-${textureName.value}-black.jpg`
65
+ }
66
+ return `texture-${textureName.value}.jpg`
67
+ })
68
+ const backgroundUrl = computed((): string =>{
69
+ return `${props.backgroundBaseUrl}/assets/img/${filename.value}`
70
+ })
71
+ const backgroundSize = computed((): string =>{
72
+ return props.size
73
+ })
74
+ const backgroundImage = computed((): string =>{
75
+ return `url("${backgroundUrl.value}")`
76
+ })
77
+ const inheritedProps = computed((): object =>{
78
+ return { ...attrs, ...props, tag: undefined }
79
+ })
80
+ return {
81
+ backgroundSize,
82
+ backgroundImage,
83
+ inheritedProps
84
+ }
85
+ }
86
+ })
87
+ </script>
88
+
89
+ <template>
90
+ <component :is="tag" :style="{ backgroundSize, backgroundImage }" v-bind="inheritedProps" class="textured-deck">
91
+ <slot />
92
+ </component>
93
+ </template>
94
+
95
+ <style lang="scss" scoped>
96
+ .textured-deck {
97
+ background: #000 no-repeat center center;
98
+ background-size: cover;
99
+ color: #fff;
100
+ }
101
+ </style>
@@ -0,0 +1,268 @@
1
+ <template>
2
+ <div class="tiny-pagination" :class="paginationClassList">
3
+ <b-button
4
+ class="tiny-pagination__nav"
5
+ :size="size"
6
+ :disabled="!hasPrevious"
7
+ :variant="navVariant"
8
+ @click="applyPreviousPage"
9
+ >
10
+ <!-- @slot Previous button content -->
11
+ <slot name="previous" v-bind="{ modelValue, numberOfPages, hasPrevious, hasNext }">
12
+ <fa :icon="previousPageIcon" />
13
+ <span class="sr-only">{{ t('tiny-pagination.previous') }}</span>
14
+ </slot>
15
+ </b-button>
16
+ <form class="tiny-pagination__form form-inline" @submit.prevent="applyPageForm">
17
+ <label v-show="!compact" class="tiny-pagination__form__label me-1 mb-0">
18
+ <!-- @slot Display page label -->
19
+ <slot name="page" v-bind="{ modelValue, numberOfPages }">
20
+ {{ t('tiny-pagination.page') }}
21
+ </slot>
22
+ </label>
23
+ <b-form-input
24
+ v-model="currentPageInput"
25
+ :size="size"
26
+ class="tiny-pagination__form__input me-1"
27
+ type="number"
28
+ step="1"
29
+ :min="1"
30
+ :max="numberOfPages"
31
+ :aria-label="t('tiny-pagination.aria')"
32
+ />
33
+ <!-- @slot Display number of pages -->
34
+ <slot name="number-of-pages" v-bind="{ modelValue, numberOfPages }">
35
+ {{ t('tiny-pagination.total', { numberOfPages }) }}
36
+ </slot>
37
+ </form>
38
+ <b-button
39
+ class="tiny-pagination__nav"
40
+ :size="size"
41
+ :disabled="!hasNext"
42
+ :variant="navVariant"
43
+ @click="applyNextPage"
44
+ >
45
+ <!-- @slot Next button content -->
46
+ <slot name="next" v-bind="{ modelValue, numberOfPages, hasPrevious, hasNext }">
47
+ <fa :icon="nextPageIcon" />
48
+ <span class="sr-only">{{ t('tiny-pagination.next') }}</span>
49
+ </slot>
50
+ </b-button>
51
+ </div>
52
+ </template>
53
+
54
+ <script lang="ts">
55
+ import { faAngleLeft, faAngleRight } from '@fortawesome/free-solid-svg-icons'
56
+ import { defineComponent, PropType, ref, computed, watch, onBeforeMount } from 'vue'
57
+ import {useI18n} from "vue-i18n";
58
+
59
+ import { library, default as Fa } from './Fa'
60
+
61
+ import { Size } from '@/enums'
62
+ import { ButtonVariant, BFormInput, BButton } from 'bootstrap-vue-next'
63
+
64
+ export default defineComponent({
65
+ name: 'TinyPagination',
66
+ components: {
67
+ Fa,
68
+ BFormInput,
69
+ BButton
70
+ },
71
+ props: {
72
+ /**
73
+ * Total items to be stored in pages
74
+ */
75
+ totalRows: {
76
+ type: Number,
77
+ default: 0
78
+ },
79
+ /**
80
+ * Sets the quantity of items per page
81
+ */
82
+ perPage: {
83
+ type: Number,
84
+ default: 20
85
+ },
86
+ /**
87
+ * Grabs and syncs the currentPage variable passed down from the parent in v-model
88
+ */
89
+ modelValue: {
90
+ type: [Number, String],
91
+ default: 1
92
+ },
93
+ /**
94
+ * Set the size of the input: 'sm', 'md' (default), or 'lg'.
95
+ */
96
+ size: {
97
+ type: String as PropType<Size>,
98
+ default: Size.md,
99
+ validator: (value: Size) => Object.values(Size).includes(value)
100
+ },
101
+ /**
102
+ * (Optional) Number of page. Property `size` is required for this to work
103
+ * properly. If `pages` is empty, it will be calculated using the size.
104
+ */
105
+ pages: {
106
+ type: [Number, String],
107
+ default: null
108
+ },
109
+ /**
110
+ * Hide navigation buttons (next and previous)
111
+ */
112
+ noNav: {
113
+ type: Boolean
114
+ },
115
+ /**
116
+ * FontAwesome icon of the previous page button
117
+ */
118
+ previousPageIcon: {
119
+ type: [String, Array, Object],
120
+ default: 'angle-left'
121
+ },
122
+ /**
123
+ * FontAwesome icon of the next page button
124
+ */
125
+ nextPageIcon: {
126
+ type: [String, Array, Object],
127
+ default: 'angle-right'
128
+ },
129
+ /**
130
+ * Navigation button variants
131
+ */
132
+ navVariant: {
133
+ type: String as PropType<ButtonVariant>,
134
+ default: 'link'
135
+ },
136
+ /**
137
+ * Display pagination as a block (full width)
138
+ */
139
+ block: {
140
+ type: Boolean
141
+ },
142
+ /**
143
+ * Compact mode with a grouped nav
144
+ */
145
+ compact: {
146
+ type: Boolean
147
+ }
148
+ },
149
+ emits:['update:modelValue'],
150
+ setup(props,{emit}) {
151
+
152
+ onBeforeMount(()=> {
153
+ library.add(faAngleLeft, faAngleRight)
154
+ })
155
+
156
+ const { t } = useI18n()
157
+ const pageValue = computed(()=>{return +props.modelValue})
158
+ const currentPageInput = ref<number|string>(pageValue.value)
159
+ const numberOfPages = computed((): number =>{
160
+ if (props.pages === null) {
161
+ return Math.ceil(props.totalRows / props.perPage)
162
+ }
163
+ return Number(props.pages)
164
+ })
165
+ const paginationClassList = computed((): object =>{
166
+ return {
167
+ [`tiny-pagination--${props.size}`]: true,
168
+ [`tiny-pagination--no-nav`]: props.noNav,
169
+ [`tiny-pagination--block`]: props.block,
170
+ [`tiny-pagination--compact`]: props.compact
171
+ }
172
+ })
173
+ const hasPrevious = computed((): boolean =>{
174
+ return pageValue.value > 1
175
+ })
176
+ const hasNext = computed((): boolean =>{
177
+ return pageValue.value < numberOfPages.value
178
+ })
179
+ function applyPageForm(): void {
180
+ if (!isNaN(currentPageInput.value as number)) {
181
+ emit('update:modelValue', +currentPageInput.value)
182
+ }
183
+ }
184
+
185
+ function applyNextPage(): void {
186
+ emit('update:modelValue', pageValue.value - 1)
187
+ }
188
+ function applyPreviousPage(): void {
189
+ emit('update:modelValue', pageValue.value + 1)
190
+ }
191
+ return {
192
+ t,
193
+ currentPageInput,
194
+ paginationClassList,
195
+ numberOfPages,
196
+ hasPrevious,
197
+ hasNext,
198
+ applyPreviousPage,
199
+ applyNextPage,
200
+ applyPageForm
201
+ }
202
+ }
203
+ })
204
+ </script>
205
+
206
+ <style lang="scss" scoped>
207
+ @import '../styles/lib';
208
+
209
+ .tiny-pagination {
210
+ display: inline-flex;
211
+ align-items: center;
212
+ justify-content: center;
213
+ text-align: center;
214
+
215
+ &--block {
216
+ display: flex;
217
+ }
218
+
219
+ &--sm {
220
+ font-size: $font-size-sm;
221
+ }
222
+
223
+ &--lg {
224
+ font-size: $font-size-lg;
225
+ }
226
+
227
+ &--no-nav &__nav {
228
+ display: none;
229
+ }
230
+
231
+ &--no-nav &__form {
232
+ margin: 0;
233
+ }
234
+
235
+ &--compact &__nav {
236
+ order: 0;
237
+ }
238
+
239
+ &--compact &__form {
240
+ order: 10;
241
+ }
242
+
243
+ &__form {
244
+ margin: 0 $spacer * 0.25;
245
+ width: 100%;
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+
250
+ &__input {
251
+ max-width: 2.5rem;
252
+ padding-left: 0.2rem;
253
+ padding-right: 0.2rem;
254
+ text-align: center;
255
+
256
+ &[type='number'] {
257
+ -moz-appearance: textfield;
258
+
259
+ &::-webkit-outer-spin-button,
260
+ &::-webkit-inner-spin-button {
261
+ -webkit-appearance: none;
262
+ margin: 0;
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ </style>
@@ -0,0 +1,31 @@
1
+ export { default as AccordionWrapper } from './AccordionWrapper.vue'
2
+ export { default as AccordionStep } from './AccordionStep.vue'
3
+ export { default as ActiveTextTruncate } from './ActiveTextTruncate.vue'
4
+ export { default as AdvancedLinkForm } from './AdvancedLinkForm.vue'
5
+ export { default as BrandExpansion } from './BrandExpansion.vue'
6
+ export { default as Brand } from './Brand.vue'
7
+ export { default as ConfirmButton } from './ConfirmButton.vue'
8
+ export { default as ContentPlaceholder } from './ContentPlaceholder.vue'
9
+ export { default as CustomPagination } from './CustomPagination.vue'
10
+ export { default as DigitsInput } from './DigitsInput.vue'
11
+ export { default as DonateForm } from './DonateForm.vue'
12
+ export { default as EmbeddableFooter } from './EmbeddableFooter.vue'
13
+ export { default as EmbedForm } from './EmbedForm.vue'
14
+ export { default as FollowUsPopover } from './FollowUsPopover.vue'
15
+ export { default as Fa } from './Fa'
16
+ export { default as GenericFooter } from './GenericFooter.vue'
17
+ export { default as GenericHeader } from './GenericHeader.vue'
18
+ export { default as HapticCopy } from './HapticCopy.vue'
19
+ export { default as ImddbHeader } from './ImddbHeader.vue'
20
+ export { default as OrdinalLegend } from './OrdinalLegend.vue'
21
+ export { default as RangePicker } from './RangePicker.vue'
22
+ export { default as ResponsiveIframe } from './ResponsiveIframe.vue'
23
+ export { default as ScaleLegend } from './ScaleLegend.vue'
24
+ export { default as SelectableDropdown } from './SelectableDropdown.vue'
25
+ export { default as SecretInput } from './SecretInput.vue'
26
+ export { default as SharingOptions } from './SharingOptions.vue'
27
+ export { default as SharingOptionsLink } from './SharingOptionsLink.vue'
28
+ export { default as SignUpForm } from './SignUpForm.vue'
29
+ export { default as SlideUpDown } from './SlideUpDown.vue'
30
+ export { default as TexturedDeck } from './TexturedDeck.vue'
31
+ export { default as TinyPagination } from './TinyPagination.vue'
@@ -0,0 +1,182 @@
1
+ import * as d3 from 'd3'
2
+ import isFunction from 'lodash/isFunction'
3
+ import isObject from 'lodash/isObject'
4
+ import isString from 'lodash/isString'
5
+ import max from 'lodash/max'
6
+ import some from 'lodash/some'
7
+ import {ComponentPublicInstance, computed, onMounted, ref, watch} from 'vue'
8
+ import {isUrl} from '@/utils/strings'
9
+ import { Ref, SetupContext} from "@vue/runtime-core";
10
+ import useResizeObserver from "@/composables/resizeObserver";
11
+ import { watchEffect } from 'vue'
12
+
13
+
14
+ type ChartContext<T extends string[]> = SetupContext<[...T, ...string[]]>;
15
+ type ChartEmit = Pick<ChartContext<["resized", "loaded"]>, 'emit'>
16
+ type ChartProps = {
17
+ chartHeightRatio: { type: NumberConstructor },
18
+ data: {
19
+ default: () => any[] | string,
20
+ validator(value: string): boolean,
21
+ type: (ArrayConstructor | StringConstructor | ObjectConstructor)[]
22
+ },
23
+ dataUrlType: { default: string, validator(value: string): boolean, type: StringConstructor },
24
+ socialMode: { type: BooleanConstructor },
25
+ socialModeRatio:
26
+ { default: number, type: NumberConstructor }
27
+ };
28
+
29
+ export function getChartProps(props: any): ChartProps {
30
+ return {
31
+ chartHeightRatio: props.chartHeightRatio,
32
+ data: props.data,
33
+ dataUrlType: props.dataUrlType,
34
+ socialMode: props.socialMode,
35
+ socialModeRatio: props.socialModeRatio,
36
+ }
37
+ }
38
+
39
+ export const chartProps = (): ChartProps => ({
40
+ data: {
41
+ type: [Array, String, Object],
42
+ default: () => [],
43
+ validator(value: string) {
44
+ return isObject(value) || (isString(value) && isUrl(value))
45
+ }
46
+ },
47
+ /**
48
+ * Format of the data to load.
49
+ */
50
+ dataUrlType: {
51
+ type: String,
52
+ default: 'json',
53
+ validator(value: string) {
54
+ return ['json', 'csv', 'tsv'].indexOf(value) > -1
55
+ }
56
+ },
57
+ /**
58
+ * When applicable, default chart's height ratio
59
+ */
60
+ chartHeightRatio: {
61
+ type: Number
62
+ },
63
+ /**
64
+ * If true, the chart will be display on social mode
65
+ */
66
+ socialMode: {
67
+ type: Boolean
68
+ },
69
+ /**
70
+ * Ratio to use in social mode
71
+ */
72
+ socialModeRatio: {
73
+ type: Number,
74
+ default: 5 / 4
75
+ }
76
+ })
77
+ export const chartEmits = ["resized", "loaded"]
78
+ type Chart = {
79
+ dataHasHighlights: any;
80
+ loadedData: any;
81
+ xAxisYearFormat: (year: (number | string)) => number | string;
82
+ elementsMaxBBox: ({selector, defaultWidth, defaultHeight}?: {
83
+ selector?: any;
84
+ defaultWidth?: any;
85
+ defaultHeight?: any
86
+ }) => ({ width: any; height: any });
87
+ d3Formatter: any;
88
+ baseHeightRatio: any
89
+ }
90
+ export function useChart(resizableRef: Ref<ComponentPublicInstance<HTMLElement> | null>, props: ChartProps, {emit}: ChartEmit, isLoaded:Ref<boolean>, onResized?:Function, afterLoaded?:()=>Promise<any>): Chart {
91
+ const { resizeRef , resizeState } = useResizeObserver(resizableRef)
92
+ const loadedData = ref([])
93
+
94
+ onMounted(async () => {
95
+ await document.fonts?.ready
96
+
97
+ watchEffect(async ()=>{
98
+ if(!isLoaded.value){
99
+
100
+ if (isString(props.data)) {
101
+ // @ts-ignore
102
+ loadedData.value = await d3[props.dataUrlType](props.data)
103
+ } else {
104
+ loadedData.value = props.data as unknown as []
105
+ }
106
+
107
+ if(afterLoaded){
108
+ await afterLoaded()
109
+ }
110
+ isLoaded.value = true
111
+ emit('loaded')
112
+ }
113
+
114
+ if(isLoaded.value && onResized){
115
+ onResized()
116
+ emit('resized')
117
+ }
118
+ })
119
+
120
+
121
+ })
122
+ function elementsMaxBBox({selector = 'text', defaultWidth = null, defaultHeight = null} = {}) {
123
+
124
+ const elements = isLoaded.value? resizeRef.value?.querySelectorAll(selector) : []
125
+ if (elements.length == 0) {
126
+ return {width: defaultWidth, height: defaultHeight}
127
+ }
128
+ const width = max(
129
+ [...elements].map((l) => {
130
+ return l.getBBox ? l.getBBox().width : defaultWidth
131
+ })
132
+ )
133
+ const height = max(
134
+ [...elements].map((l) => {
135
+ return l.getBBox ? l.getBBox().height : defaultHeight
136
+ })
137
+ )
138
+ return {width, height}
139
+ }
140
+
141
+ function xAxisYearFormat(year: number | string) {
142
+ // previously using narrowWidth but it is automatically updated through resizeObserver state reactivity
143
+ return resizeState.narrowWidth ? '’' + String(year).slice(2, 4) : year
144
+ }
145
+ function highlighted(datum: { highlight: boolean }) {
146
+ return datum.highlight
147
+ }
148
+ function d3Formatter(value:any,formatter:any) {
149
+ if (isFunction(formatter)) {
150
+ return formatter(value)
151
+ } else if (isString(formatter)) {
152
+ return d3.format(formatter)(value)
153
+ }
154
+ return value
155
+ }
156
+ const baseHeightRatio = computed(() => {
157
+ return props.chartHeightRatio || (props.socialMode ? props.socialModeRatio : 9 / 16)
158
+ })
159
+ const dataHasHighlights = computed(() => {
160
+ if (Array.isArray(props.data)) {
161
+ return some(props.data, highlighted)
162
+ }
163
+ return false
164
+ })
165
+
166
+ watch(resizeState.dimensions, () => {
167
+ if(isLoaded.value && onResized){
168
+ onResized()
169
+ emit('resized')
170
+ }
171
+ })
172
+
173
+
174
+ return {
175
+ loadedData,
176
+ elementsMaxBBox,
177
+ xAxisYearFormat,
178
+ d3Formatter,
179
+ baseHeightRatio,
180
+ dataHasHighlights,
181
+ }
182
+ }