@icij/murmur-next 4.8.3 → 4.9.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 (43) hide show
  1. package/dist/lib/lib/components/App/AppHeader.vue.d.ts +4 -0
  2. package/dist/lib/lib/components/EmbeddableFooter/EmbeddableFooter.vue.d.ts +8 -0
  3. package/dist/lib/lib/components/FollowUsPopover/FollowUsPopover.vue.d.ts +6 -0
  4. package/dist/lib/lib/components/Form/FormEmbed.vue.d.ts +4 -0
  5. package/dist/lib/lib/components/Form/FormSignUp.vue.d.ts +4 -0
  6. package/dist/lib/lib/components/SharingOptions/SharingOptionsLink.vue.d.ts +2 -1
  7. package/dist/lib/lib/config.default.d.ts +0 -1
  8. package/dist/lib/lib/enums.d.ts +1 -2
  9. package/dist/lib/murmur.css +1 -1
  10. package/dist/lib/murmur.js +6316 -6301
  11. package/dist/lib/murmur.js.map +1 -1
  12. package/dist/lib/murmur.umd.cjs +16 -16
  13. package/dist/lib/murmur.umd.cjs.map +1 -1
  14. package/dist/lib/stories/murmur/decorators.d.ts +2 -1
  15. package/lib/assets/images/icij-full-white.svg +0 -0
  16. package/lib/assets/images/icij-full.svg +0 -0
  17. package/lib/assets/images/icij.png +0 -0
  18. package/lib/assets/images/icij.svg +0 -0
  19. package/lib/assets/images/icij@2x.png +0 -0
  20. package/lib/assets/images/murmur-dark.png +0 -0
  21. package/lib/assets/images/murmur-dark.svg +0 -0
  22. package/lib/assets/images/murmur-textured.png +0 -0
  23. package/lib/assets/images/murmur-white.png +0 -0
  24. package/lib/assets/images/murmur-white.svg +0 -0
  25. package/lib/components/App/AppHeader.vue +8 -2
  26. package/lib/components/EmbeddableFooter/EmbeddableFooter.vue +18 -4
  27. package/lib/components/FollowUsPopover/FollowUsPopover.vue +18 -5
  28. package/lib/components/Form/FormEmbed.vue +15 -15
  29. package/lib/components/Form/FormSignUp.vue +39 -3
  30. package/lib/components/SharingOptions/SharingOptions.vue +13 -19
  31. package/lib/components/SharingOptions/SharingOptionsLink.vue +20 -39
  32. package/lib/config.default.ts +0 -1
  33. package/lib/enums.ts +1 -2
  34. package/lib/keys.ts +0 -0
  35. package/lib/locales/fr.json +0 -0
  36. package/lib/styles/lib.scss +0 -0
  37. package/lib/styles/utilities.scss +0 -0
  38. package/lib/styles/variables_dark.scss +0 -0
  39. package/lib/types/d3-geo-projection.d.ts +0 -0
  40. package/lib/types/querystring-es3.d.ts +0 -0
  41. package/lib/types/shims-bootstrap-vue.d.ts +0 -0
  42. package/lib/utils/clipboard.ts +0 -0
  43. package/package.json +1 -1
@@ -7,7 +7,8 @@ export declare const modalDecorator: (buttonLabel: string | undefined, modalTitl
7
7
  BModal: any;
8
8
  };
9
9
  setup(): {
10
- show: (id?: import('bootstrap-vue-next').ControllerKey) => void;
10
+ visible: any;
11
+ show: () => void;
11
12
  buttonLabel: string;
12
13
  modalTitle: string | null;
13
14
  size: keyof import('bootstrap-vue-next').BaseSize;
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -93,10 +93,11 @@
93
93
  <b-popover
94
94
  v-model="showFollowUsPopover"
95
95
  target="follow-us-toggler"
96
- placement="bottom-start"
96
+ placement="bottom-end"
97
97
  click
98
98
  >
99
99
  <follow-us-popover
100
+ :compact="compactSignUp"
100
101
  @update:close="closeFollowUsPopover"
101
102
  @keydown.esc="closeFollowUsPopover"
102
103
  />
@@ -135,13 +136,18 @@ export interface AppHeaderProps {
135
136
  * Target link of the donate button.
136
137
  */
137
138
  donateUrl?: string
139
+ /**
140
+ * Compact layout for the sign-up form in the follow-us popover.
141
+ */
142
+ compactSignUp?: boolean
138
143
  }
139
144
 
140
145
  const props = withDefaults(defineProps<AppHeaderProps>(), {
141
146
  position: 'fixed',
142
147
  noHeadroom: false,
143
148
  homeUrl: () => config.get('app.home'),
144
- donateUrl: () => config.get('app.donate-url')
149
+ donateUrl: () => config.get('app.donate-url'),
150
+ compactSignUp: false
145
151
  })
146
152
 
147
153
  const { t } = useI18n()
@@ -4,9 +4,10 @@
4
4
  :href="homeUrl"
5
5
  target="_blank"
6
6
  class="text-white embeddable-footer__brand"
7
+ :class="{ 'embeddable-footer__brand--no-divider': hideDivider }"
7
8
  >
8
9
  <brand
9
- :size="40"
10
+ :size="logoHeight"
10
11
  no-border
11
12
  class="me-2"
12
13
  color="white"
@@ -82,6 +83,14 @@ export interface EmbeddableFooterProps {
82
83
  * Sharing option values to bind to the sharing-options component in the bottom-right corner.
83
84
  */
84
85
  sharingOptionsValues?: Record<string, unknown>
86
+ /**
87
+ * Hide the divider (right border) next to the brand.
88
+ */
89
+ hideDivider?: boolean
90
+ /**
91
+ * Height of the logo in pixels.
92
+ */
93
+ logoHeight?: number | string
85
94
  }
86
95
 
87
96
  withDefaults(defineProps<EmbeddableFooterProps>(), {
@@ -90,7 +99,9 @@ withDefaults(defineProps<EmbeddableFooterProps>(), {
90
99
  iframeMinHeight: 100,
91
100
  iframeMinWidth: 100,
92
101
  homeUrl: () => config.get('app.home'),
93
- sharingOptionsValues: () => ({})
102
+ sharingOptionsValues: () => ({}),
103
+ hideDivider: false,
104
+ logoHeight: 40
94
105
  })
95
106
 
96
107
  // Reactive state
@@ -103,7 +114,6 @@ onMounted(() => {
103
114
  </script>
104
115
 
105
116
  <style lang="scss" scoped>
106
-
107
117
  @import '../../styles/mixins';
108
118
 
109
119
  @include keyframes(slideup) {
@@ -146,6 +156,10 @@ onMounted(() => {
146
156
  display: flex;
147
157
  justify-content: center;
148
158
  align-items: center;
159
+
160
+ &--no-divider {
161
+ border-right: none;
162
+ }
149
163
  }
150
164
  &__lead {
151
165
  flex-grow: 1;
@@ -176,7 +190,7 @@ onMounted(() => {
176
190
  right: 0;
177
191
  margin: $spacer * 0.25;
178
192
 
179
- .sharing-options__link {
193
+ &:deep(.sharing-options__link) {
180
194
  opacity: 0;
181
195
  animation: slideup 200ms forwards;
182
196
  @include animation-delay-loop(0, 10, 50ms);
@@ -4,9 +4,14 @@
4
4
  class="btn btn-link text-secondary follow-us__close"
5
5
  @click="closeSignupPopover"
6
6
  >
7
- <app-icon><i-ph-x /></app-icon>
7
+ <app-icon>
8
+ <i-ph-x-bold />
9
+ </app-icon>
8
10
  </button>
9
- <sign-up-form class="p-3" />
11
+ <sign-up-form
12
+ class="p-3"
13
+ :compact="compact"
14
+ />
10
15
  <div class="px-3 pb-1 text-uppercase text-muted fw-bold">
11
16
  {{ t('follow-us-popover.heading') }}
12
17
  </div>
@@ -59,9 +64,17 @@ import { useI18n } from 'vue-i18n'
59
64
  import SignUpForm from '@/components/Form/FormSignUp.vue'
60
65
  import AppIcon from '@/components/App/AppIcon.vue'
61
66
 
62
- /**
63
- * FollowUsPopover
64
- */
67
+ export interface FollowUsPopoverProps {
68
+ /**
69
+ * Compact layout for the sign-up form.
70
+ */
71
+ compact?: boolean
72
+ }
73
+
74
+ withDefaults(defineProps<FollowUsPopoverProps>(), {
75
+ compact: false
76
+ })
77
+
65
78
  const emit = defineEmits(['update:close'])
66
79
  const { t } = useI18n()
67
80
 
@@ -2,6 +2,7 @@
2
2
  import { computed, ref } from 'vue'
3
3
 
4
4
  import { useI18n } from 'vue-i18n'
5
+ import { BFormCheckbox } from 'bootstrap-vue-next'
5
6
  import HapticCopy from '@/components/HapticCopy/HapticCopy.vue'
6
7
  import IframeResizer from '@/utils/iframe-resizer'
7
8
 
@@ -38,6 +39,10 @@ export interface FormEmbedProps {
38
39
  * URL of the iframe code
39
40
  */
40
41
  url?: string | null
42
+ /**
43
+ * Use a switch display for the responsive iframe checkbox
44
+ */
45
+ switchResponsive?: boolean
41
46
  }
42
47
 
43
48
  const props = withDefaults(defineProps<FormEmbedProps>(), {
@@ -47,7 +52,8 @@ const props = withDefaults(defineProps<FormEmbedProps>(), {
47
52
  height: () => window.innerHeight,
48
53
  minWidth: 0,
49
54
  minHeight: 0,
50
- url: null
55
+ url: null,
56
+ switchResponsive: false
51
57
  })
52
58
 
53
59
  const { t } = useI18n()
@@ -107,20 +113,14 @@ function embedCode(withPym = responsiveCheck.value): string {
107
113
  />
108
114
 
109
115
  <div class="d-flex justify-content-between">
110
- <div class="form-check align-self-end">
111
- <input
112
- id="responsiveOptin"
113
- v-model="responsiveCheck"
114
- type="checkbox"
115
- class="form-check-input"
116
- >
117
- <label
118
- class="form-check-label fw-bold"
119
- for="responsiveOptin"
120
- >
121
- {{ t('embed-form.responsive-optin') }}
122
- </label>
123
- </div>
116
+ <b-form-checkbox
117
+ id="responsiveOptin"
118
+ v-model="responsiveCheck"
119
+ class="align-self-end fw-bold"
120
+ :switch="switchResponsive"
121
+ >
122
+ {{ t('embed-form.responsive-optin') }}
123
+ </b-form-checkbox>
124
124
 
125
125
  <haptic-copy
126
126
  class="btn-link btn-sm text-uppercase fw-bold"
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <form
3
3
  class="sign-up-form"
4
- :class="{ 'sign-up-form--horizontal': horizontal }"
4
+ :class="classList"
5
5
  @submit.prevent="subscribe"
6
6
  >
7
7
  <fieldset :disabled="frozen">
8
8
  <label
9
9
  v-if="!noLabel"
10
- class="text-uppercase text-muted fw-bold"
10
+ class="sign-up-form__fieldset__label text-uppercase text-muted fw-bold"
11
11
  for="input-email"
12
12
  >
13
13
  {{ t('sign-up-form.label') }}
@@ -90,6 +90,10 @@ export interface FormSignUpProps {
90
90
  * Color variant of the sign-up button
91
91
  */
92
92
  variant?: ButtonVariant
93
+ /**
94
+ * Compact layout with no gap between the input and the submit button.
95
+ */
96
+ compact?: boolean
93
97
  }
94
98
 
95
99
  const props = withDefaults(defineProps<FormSignUpProps>(), {
@@ -100,7 +104,8 @@ const props = withDefaults(defineProps<FormSignUpProps>(), {
100
104
  horizontal: false,
101
105
  tracker: () => config.get('signup-form.tracker'),
102
106
  referrer: null,
103
- variant: 'primary'
107
+ variant: 'primary',
108
+ compact: false
104
109
  })
105
110
  const emit = defineEmits(['error', 'success', 'subscribed'])
106
111
  const { t } = useI18n()
@@ -117,6 +122,11 @@ const { send } = useSendEmail(
117
122
  props.defaultGroups
118
123
  )
119
124
 
125
+ const classList = computed(() => ({
126
+ 'sign-up-form--horizontal': props.horizontal,
127
+ 'sign-up-form--compact': props.compact,
128
+ }))
129
+
120
130
  const variantColorClass = computed(() => {
121
131
  return `btn-${props.variant}`
122
132
  })
@@ -170,6 +180,32 @@ function unfreeze() {
170
180
  <style lang="scss">
171
181
 
172
182
  .sign-up-form {
183
+ .sign-up-form__fieldset {
184
+ &__label {
185
+ margin-bottom: $spacer-xs;
186
+ }
187
+
188
+ &__group {
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: $spacer-xs;
192
+ }
193
+ }
194
+
195
+ &--horizontal .sign-up-form__fieldset__group {
196
+ flex-direction: row;
197
+ }
198
+
199
+ &--compact {
200
+ .sign-up-form__fieldset__label {
201
+ margin-bottom: 0;
202
+ }
203
+
204
+ .sign-up-form__fieldset__group {
205
+ gap: 0;
206
+ }
207
+ }
208
+
173
209
  .sign-up-form__fieldset__group__addon.btn {
174
210
  font-size: 0.9em;
175
211
  }
@@ -1,9 +1,9 @@
1
1
  <script setup lang="ts">
2
2
  import get from 'lodash/get'
3
3
  import reduce from 'lodash/reduce'
4
- import uniqueId from 'lodash/uniqueId'
5
4
  import {
6
5
  computed,
6
+ ref,
7
7
  type CSSProperties
8
8
  } from 'vue'
9
9
 
@@ -12,7 +12,7 @@ import AppIcon from '@/components/App/AppIcon.vue'
12
12
  import SharingOptionsLink from '@/components/SharingOptions/SharingOptionsLink.vue'
13
13
  import config from '@/config'
14
14
  import IframeResizer from '@/utils/iframe-resizer'
15
- import { BModal, useModal } from 'bootstrap-vue-next'
15
+ import { BModal } from 'bootstrap-vue-next'
16
16
 
17
17
  interface MetaValuesMap {
18
18
  url: string
@@ -21,8 +21,6 @@ interface MetaValuesMap {
21
21
  facebook_title: string
22
22
  facebook_description: string
23
23
  facebook_media: string
24
- twitter_media: string
25
- twitter_user: string
26
24
  }
27
25
 
28
26
  export interface SharingOptionsProps {
@@ -77,8 +75,10 @@ const props = withDefaults(defineProps<SharingOptionsProps>(), {
77
75
  noMeta: false
78
76
  })
79
77
 
80
- const embedFormId = uniqueId('embed-form-')
81
- const { show } = useModal(embedFormId)
78
+ const showEmbedForm = ref(false)
79
+ const show = () => {
80
+ showEmbedForm.value = true
81
+ }
82
82
  const style = computed((): CSSProperties => {
83
83
  return {
84
84
  'flex-direction': props.direction
@@ -105,14 +105,6 @@ const metaValues = computed((): MetaValuesMap => {
105
105
  'sharing-options.media',
106
106
  'meta[property="og:image"]'
107
107
  ),
108
- twitter_media: defaultValueFor(
109
- 'sharing-options.media',
110
- 'meta[name="twitter:image"]'
111
- ),
112
- twitter_user: defaultValueFor(
113
- 'sharing-options.twitter-user',
114
- 'meta[name="twitter:site"]'
115
- )
116
108
  }
117
109
  })
118
110
 
@@ -152,8 +144,8 @@ function defaultValueFor(key: string, metaSelector?: string): string {
152
144
  />
153
145
  <sharing-options-link
154
146
  class="sharing-options__link"
155
- network="twitter"
156
- v-bind="valuesFor('twitter')"
147
+ network="bluesky"
148
+ v-bind="valuesFor('bluesky')"
157
149
  />
158
150
  <sharing-options-link
159
151
  class="sharing-options__link"
@@ -170,13 +162,15 @@ function defaultValueFor(key: string, metaSelector?: string): string {
170
162
  class="sharing-options__link sharing-options__link--embed"
171
163
  @click="show"
172
164
  >
173
- <app-icon><i-ph-code /></app-icon>
165
+ <app-icon>
166
+ <i-ph-code-bold />
167
+ </app-icon>
174
168
  <span class="visually-hidden">Embed</span>
175
169
  </a>
176
170
  <b-modal
177
- :id="embedFormId"
171
+ v-model="showEmbedForm"
178
172
  class="text-dark"
179
- hide-footer
173
+ no-footer
180
174
  title="Embed on your website"
181
175
  >
182
176
  <embed-form
@@ -12,11 +12,16 @@ export const $popup: Popup = {
12
12
  parent: typeof window !== 'undefined' ? window : null
13
13
  }
14
14
 
15
+ import type { Component } from 'vue'
15
16
  import { SharingPlatform } from '@/enums'
17
+ import IPhEnvelope from '~icons/ph/envelope-bold'
18
+ import IPhFacebookLogoFill from '~icons/ph/facebook-logo-fill'
19
+ import IPhLinkedinLogoFill from '~icons/ph/linkedin-logo-fill'
20
+ import IPhButterflyFill from '~icons/ph/butterfly-fill'
16
21
 
17
22
  interface SharingPlatformConfig {
18
23
  base: string
19
- icon: string
24
+ icon: Component
20
25
  args: Record<string, string>
21
26
  }
22
27
 
@@ -27,7 +32,7 @@ type SharingPlatforms = Record<SharingPlatform, SharingPlatformConfig>
27
32
  export const networks: SharingPlatforms = {
28
33
  email: {
29
34
  base: 'mailto:?',
30
- icon: 'envelope',
35
+ icon: IPhEnvelope,
31
36
  args: {
32
37
  subject: 'title',
33
38
  body: 'description'
@@ -35,7 +40,7 @@ export const networks: SharingPlatforms = {
35
40
  },
36
41
  facebook: {
37
42
  base: 'https://www.facebook.com/sharer.php?',
38
- icon: 'facebook-logo',
43
+ icon: IPhFacebookLogoFill,
39
44
  args: {
40
45
  u: 'url',
41
46
  title: 'title',
@@ -45,31 +50,19 @@ export const networks: SharingPlatforms = {
45
50
  },
46
51
  linkedin: {
47
52
  base: 'https://www.linkedin.com/sharing/share-offsite/?',
48
- icon: 'linkedin-logo',
53
+ icon: IPhLinkedinLogoFill,
49
54
  args: {
50
55
  url: 'url',
51
56
  title: 'title',
52
57
  summary: 'description'
53
58
  }
54
59
  },
55
- twitter: {
56
- base: 'https://x.com/intent/tweet?',
57
- icon: 'x-logo',
58
- args: {
59
- url: 'url',
60
- text: 'title',
61
- via: 'user',
62
- hashtags: 'hashtags'
63
- }
64
- },
65
- x: {
66
- base: 'https://x.com/intent/tweet?',
67
- icon: 'x-logo',
60
+ bluesky: {
61
+ base: 'https://bsky.app/intent/compose?',
62
+ icon: IPhButterflyFill,
68
63
  args: {
69
- url: 'url',
70
64
  text: 'title',
71
- via: 'user',
72
- hashtags: 'hashtags'
65
+ url: 'url'
73
66
  }
74
67
  }
75
68
  }
@@ -79,20 +72,9 @@ export const networks: SharingPlatforms = {
79
72
  import querystring from 'querystring-es3'
80
73
  import reduce from 'lodash/reduce'
81
74
  import get from 'lodash/get'
82
- import { computed, reactive, type Component } from 'vue'
75
+ import { computed, reactive } from 'vue'
83
76
 
84
77
  import AppIcon from '@/components/App/AppIcon.vue'
85
- import IPhEnvelopeFill from '~icons/ph/envelope-fill'
86
- import IPhFacebookLogoFill from '~icons/ph/facebook-logo-fill'
87
- import IPhLinkedinLogoFill from '~icons/ph/linkedin-logo-fill'
88
- import IPhXLogoFill from '~icons/ph/x-logo-fill'
89
-
90
- const iconMap: Record<string, Component> = {
91
- 'envelope': IPhEnvelopeFill,
92
- 'facebook-logo': IPhFacebookLogoFill,
93
- 'linkedin-logo': IPhLinkedinLogoFill,
94
- 'x-logo': IPhXLogoFill
95
- }
96
78
 
97
79
  defineOptions({
98
80
  name: 'SharingOptionsLink'
@@ -128,7 +110,7 @@ export interface SharingOptionsLinkProps {
128
110
  */
129
111
  media?: string | null
130
112
  /**
131
- * Twitter user
113
+ * Social media user handle
132
114
  */
133
115
  user?: string | null
134
116
  /**
@@ -176,12 +158,8 @@ const args = computed((): Record<string, string> => {
176
158
  return get(networks, [props.network, 'args'], {})
177
159
  })
178
160
 
179
- const iconName = computed((): string | null => {
180
- return get(networks, [props.network, 'icon'], null)
181
- })
182
-
183
161
  const iconComponent = computed((): Component | null => {
184
- return iconName.value ? iconMap[iconName.value] ?? null : null
162
+ return get(networks, [props.network, 'icon'], null)
185
163
  })
186
164
 
187
165
  const query = computed((): Record<string, string> => {
@@ -268,7 +246,10 @@ defineExpose({
268
246
  @click="handleClick"
269
247
  >
270
248
  <slot>
271
- <app-icon v-if="!noIcon && iconComponent">
249
+ <app-icon
250
+ v-if="!noIcon && iconComponent"
251
+ size="1.2em"
252
+ >
272
253
  <component :is="iconComponent" />
273
254
  </app-icon>
274
255
  <span class="visually-hidden">{{ name }}</span>
@@ -26,7 +26,6 @@ export default {
26
26
  'sharing-options.title': 'Awesome App by ICIJ',
27
27
  'sharing-options.description': 'null',
28
28
  'sharing-options.media': null,
29
- 'sharing-options.twitter-user': 'ICIJorg',
30
29
  'signup-form.tracker': 'EXTERNAL',
31
30
  'signup-form.action':
32
31
  'https://icij.us15.list-manage.com/subscribe/post?u=0d48a33b1c24d257734cc2a79&id=992ecfdbb2',
package/lib/enums.ts CHANGED
@@ -80,8 +80,7 @@ export enum SharingPlatform {
80
80
  email = 'email',
81
81
  facebook = 'facebook',
82
82
  linkedin = 'linkedin',
83
- twitter = 'twitter',
84
- x = 'x'
83
+ bluesky = 'bluesky'
85
84
  }
86
85
 
87
86
  export enum DonatePeriod {
package/lib/keys.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icij/murmur-next",
3
- "version": "4.8.3",
3
+ "version": "4.9.0",
4
4
  "private": false,
5
5
  "description": "Murmur is ICIJ's Design System for Bootstrap 5 and Vue.js",
6
6
  "author": "promera@icij.org",