@asd20/ui-next 2.33.1 → 2.33.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/package.json +1 -1
- package/src/components/atoms/Asd20RichBodyContent/index.vue +3 -2
- package/src/components/organisms/Asd20MediaSection/index.vue +26 -5
- package/src/components/organisms/Asd20SecondaryHeader/index.vue +38 -348
- package/src/components/templates/Asd20ArticleDigestCompactTemplate/index.vue +1 -0
- package/src/components/templates/Asd20ArticleDigestTemplate/index.vue +1 -0
- package/src/components/templates/Asd20ArticleListTemplate/index.vue +1 -0
- package/src/components/templates/Asd20ArticleTemplate/index.vue +3 -2
- package/src/components/templates/Asd20CampusDetailTemplate/index.vue +1 -0
- package/src/components/templates/Asd20ClubsTemplate/index.vue +1 -0
- package/src/components/templates/Asd20DetailAlternateTemplate/index.vue +1 -0
- package/src/components/templates/Asd20DetailImageFullTemplate/index.vue +1 -0
- package/src/components/templates/Asd20DetailImageTemplate/index.vue +1 -0
- package/src/components/templates/Asd20DetailTemplate/index.vue +1 -0
- package/src/components/templates/Asd20FileListPageTemplate/index.vue +1 -0
- package/src/components/templates/Asd20GroupFeatureTemplate/index.vue +1 -0
- package/src/components/templates/Asd20ProfileTemplate/index.vue +1 -0
- package/src/components/templates/Asd20WayfindingAlternateTemplate/index.vue +1 -0
- package/src/components/templates/Asd20WayfindingImageTemplate/index.vue +1 -0
- package/src/components/templates/Asd20WayfindingTemplate/index.vue +1 -0
- package/src/helpers/excludeBodyMedia.js +96 -0
- package/src/mixins/pageTemplateMixin.js +0 -44
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.33.3](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.33.2...ui-next-v2.33.3) (2026-10-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* limit size of videos in body content; exclude videos and images already in body content from media section ([aba90ce](https://github.com/academydistrict20/asd20-ui-next/commit/aba90ceec4c244a8317cc544972fa753615da982))
|
|
9
|
+
|
|
10
|
+
## [2.33.2](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.33.1...ui-next-v2.33.2) (2026-10-26)
|
|
11
|
+
|
|
3
12
|
## [2.33.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.33.0...ui-next-v2.33.1) (2026-10-26)
|
|
4
13
|
|
|
5
14
|
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<section
|
|
3
|
-
v-
|
|
3
|
+
v-if="showImageGallery || remainingMedia.videos.length"
|
|
4
4
|
class="asd20-media-section"
|
|
5
5
|
role="complementary"
|
|
6
6
|
>
|
|
7
7
|
<slot name="before" />
|
|
8
8
|
|
|
9
9
|
<asd20-image-gallery
|
|
10
|
-
v-if="
|
|
10
|
+
v-if="showImageGallery"
|
|
11
11
|
title="Images"
|
|
12
|
-
:images="
|
|
12
|
+
:images="galleryImages"
|
|
13
13
|
>
|
|
14
14
|
</asd20-image-gallery>
|
|
15
15
|
|
|
16
16
|
<asd20-videos-section
|
|
17
|
-
v-if="videos.length > 0"
|
|
17
|
+
v-if="remainingMedia.videos.length > 0"
|
|
18
18
|
title="Videos"
|
|
19
|
-
:videos="videos"
|
|
19
|
+
:videos="remainingMedia.videos"
|
|
20
20
|
>
|
|
21
21
|
</asd20-videos-section>
|
|
22
22
|
<slot />
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<script>
|
|
27
27
|
import { defineAsyncComponent } from 'vue'
|
|
28
|
+
import excludeBodyMedia from '../../../helpers/excludeBodyMedia'
|
|
28
29
|
|
|
29
30
|
export default {
|
|
30
31
|
name: 'Asd20MediaSection',
|
|
@@ -40,6 +41,26 @@ export default {
|
|
|
40
41
|
allowSingleImageGallery: { type: Boolean, default: false },
|
|
41
42
|
images: { type: Array, default: () => [] },
|
|
42
43
|
videos: { type: Array, default: () => [] },
|
|
44
|
+
// Include only messages whose bodies are displayed on this page.
|
|
45
|
+
bodyMessages: { type: Array, default: () => [] },
|
|
46
|
+
},
|
|
47
|
+
computed: {
|
|
48
|
+
remainingMedia() {
|
|
49
|
+
return excludeBodyMedia({
|
|
50
|
+
images: this.images,
|
|
51
|
+
videos: this.videos,
|
|
52
|
+
bodyMessages: this.bodyMessages,
|
|
53
|
+
})
|
|
54
|
+
},
|
|
55
|
+
galleryImages() {
|
|
56
|
+
return this.remainingMedia.images.filter(image => !image.isCover)
|
|
57
|
+
},
|
|
58
|
+
showImageGallery() {
|
|
59
|
+
// Preserve galleries that have one image left after body duplicates
|
|
60
|
+
// are removed, while retaining the existing single-image opt-in.
|
|
61
|
+
return this.galleryImages.length > 0 &&
|
|
62
|
+
(this.allowSingleImageGallery || this.images.length > 1)
|
|
63
|
+
},
|
|
43
64
|
},
|
|
44
65
|
}
|
|
45
66
|
</script>
|
|
@@ -97,26 +97,11 @@
|
|
|
97
97
|
<div class="white-accent-band">
|
|
98
98
|
<section
|
|
99
99
|
ref="header"
|
|
100
|
-
|
|
100
|
+
class="asd20-secondary-header"
|
|
101
101
|
aria-label="Secondary message"
|
|
102
|
-
:style="secondaryHeaderStyle"
|
|
103
102
|
>
|
|
104
|
-
<!-- Parallax background (masked by .asd20-secondary-header mask) -->
|
|
105
|
-
<div
|
|
106
|
-
class="secondary-parallax"
|
|
107
|
-
aria-hidden="true"
|
|
108
|
-
>
|
|
109
|
-
<div class="secondary-parallax__layer secondary-parallax__base"></div>
|
|
110
|
-
<div
|
|
111
|
-
class="secondary-parallax__layer secondary-parallax__field"
|
|
112
|
-
></div>
|
|
113
|
-
<div
|
|
114
|
-
class="secondary-parallax__layer secondary-parallax__ribbons"
|
|
115
|
-
></div>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
103
|
<asd20-messaging
|
|
119
|
-
v-bind="
|
|
104
|
+
v-bind="secondaryMessage"
|
|
120
105
|
fullscreen
|
|
121
106
|
></asd20-messaging>
|
|
122
107
|
</section>
|
|
@@ -141,181 +126,10 @@ export default {
|
|
|
141
126
|
grid: { type: Boolean, default: false },
|
|
142
127
|
forceDisplay: { type: Boolean, default: false },
|
|
143
128
|
},
|
|
144
|
-
data() {
|
|
145
|
-
return {
|
|
146
|
-
isTouchCapableDevice: false,
|
|
147
|
-
parallaxEnabled: false,
|
|
148
|
-
intersectionObserver: null,
|
|
149
|
-
parallaxRaf: null,
|
|
150
|
-
handleScroll: null,
|
|
151
|
-
handleResize: null,
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
129
|
computed: {
|
|
155
|
-
shouldUseParallax() {
|
|
156
|
-
return !this.isTouchCapableDevice
|
|
157
|
-
},
|
|
158
|
-
headerClasses() {
|
|
159
|
-
return {
|
|
160
|
-
'asd20-secondary-header': true,
|
|
161
|
-
'asd20-secondary-header--desktop-background':
|
|
162
|
-
this.hasSecondaryHeaderImage,
|
|
163
|
-
'asd20-secondary-header--parallax-enabled-background':
|
|
164
|
-
this.hasSecondaryHeaderImage && this.shouldUseParallax,
|
|
165
|
-
'asd20-secondary-header--hide-desktop-image':
|
|
166
|
-
!this.shouldShowDesktopInlineImage,
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
130
|
secondaryMessage() {
|
|
170
131
|
return Array.isArray(this.messages) ? this.messages[1] || {} : {}
|
|
171
132
|
},
|
|
172
|
-
secondaryMessageImages() {
|
|
173
|
-
return Array.isArray(this.secondaryMessage.images)
|
|
174
|
-
? this.secondaryMessage.images
|
|
175
|
-
: []
|
|
176
|
-
},
|
|
177
|
-
secondaryHeaderImageObject() {
|
|
178
|
-
return (
|
|
179
|
-
this.secondaryMessageImages.find(image => image && image.isCover) ||
|
|
180
|
-
this.secondaryMessageImages[0] ||
|
|
181
|
-
null
|
|
182
|
-
)
|
|
183
|
-
},
|
|
184
|
-
secondaryHeaderImage() {
|
|
185
|
-
return this.resolveMessageImageUrl(this.secondaryHeaderImageObject)
|
|
186
|
-
},
|
|
187
|
-
hasSecondaryHeaderImage() {
|
|
188
|
-
return Boolean(this.secondaryHeaderImage)
|
|
189
|
-
},
|
|
190
|
-
shouldShowDesktopInlineImage() {
|
|
191
|
-
return Boolean(
|
|
192
|
-
this.secondaryHeaderImageObject && this.secondaryHeaderImageObject.isCover
|
|
193
|
-
)
|
|
194
|
-
},
|
|
195
|
-
secondaryMessageForDisplay() {
|
|
196
|
-
if (!this.secondaryHeaderImageObject) return this.secondaryMessage
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
...this.secondaryMessage,
|
|
200
|
-
images: [
|
|
201
|
-
{
|
|
202
|
-
...this.secondaryHeaderImageObject,
|
|
203
|
-
isCover: true,
|
|
204
|
-
},
|
|
205
|
-
],
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
secondaryHeaderStyle() {
|
|
209
|
-
if (!this.hasSecondaryHeaderImage) return {}
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
'--secondary-header-image': `url("${this.secondaryHeaderImage}")`,
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
mounted() {
|
|
217
|
-
if (typeof window !== 'undefined') {
|
|
218
|
-
this.isTouchCapableDevice = Boolean(
|
|
219
|
-
window.matchMedia?.('(pointer: coarse)').matches ||
|
|
220
|
-
window.navigator?.maxTouchPoints > 0
|
|
221
|
-
)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Respect reduced motion
|
|
225
|
-
const prefersReduced =
|
|
226
|
-
typeof window !== 'undefined' &&
|
|
227
|
-
window.matchMedia &&
|
|
228
|
-
window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
229
|
-
|
|
230
|
-
if (prefersReduced || !this.shouldUseParallax) return
|
|
231
|
-
|
|
232
|
-
this.handleScroll = () => this.scheduleParallaxUpdate()
|
|
233
|
-
this.handleResize = () => this.scheduleParallaxUpdate()
|
|
234
|
-
|
|
235
|
-
// Only animate when the header is in view
|
|
236
|
-
if (typeof window !== 'undefined' && 'IntersectionObserver' in window) {
|
|
237
|
-
this.intersectionObserver = new IntersectionObserver(
|
|
238
|
-
entries => {
|
|
239
|
-
const entry = entries && entries[0]
|
|
240
|
-
if (!entry) return
|
|
241
|
-
if (entry.isIntersecting) this.enableParallax()
|
|
242
|
-
else this.disableParallax()
|
|
243
|
-
},
|
|
244
|
-
{ root: null, threshold: 0.01 }
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
if (this.$refs.header) this.intersectionObserver.observe(this.$refs.header)
|
|
248
|
-
} else {
|
|
249
|
-
// Fallback: just enable
|
|
250
|
-
this.enableParallax()
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Initial set
|
|
254
|
-
this.scheduleParallaxUpdate()
|
|
255
|
-
},
|
|
256
|
-
beforeUnmount() {
|
|
257
|
-
this.teardownParallax()
|
|
258
|
-
},
|
|
259
|
-
methods: {
|
|
260
|
-
resolveMessageImageUrl(image) {
|
|
261
|
-
if (!image) return ''
|
|
262
|
-
|
|
263
|
-
const imageFiles = Array.isArray(image.files) ? image.files : []
|
|
264
|
-
const fullImage = imageFiles.find(file => file.name === 'full')
|
|
265
|
-
return fullImage ? fullImage.url : image.url || ''
|
|
266
|
-
},
|
|
267
|
-
teardownParallax() {
|
|
268
|
-
this.disableParallax()
|
|
269
|
-
if (this.intersectionObserver) this.intersectionObserver.disconnect()
|
|
270
|
-
this.intersectionObserver = null
|
|
271
|
-
},
|
|
272
|
-
enableParallax() {
|
|
273
|
-
if (this.parallaxEnabled) return
|
|
274
|
-
this.parallaxEnabled = true
|
|
275
|
-
window.addEventListener('scroll', this.handleScroll, { passive: true })
|
|
276
|
-
window.addEventListener('resize', this.handleResize, { passive: true })
|
|
277
|
-
this.scheduleParallaxUpdate()
|
|
278
|
-
},
|
|
279
|
-
disableParallax() {
|
|
280
|
-
if (!this.parallaxEnabled) return
|
|
281
|
-
this.parallaxEnabled = false
|
|
282
|
-
window.removeEventListener('scroll', this.handleScroll)
|
|
283
|
-
window.removeEventListener('resize', this.handleResize)
|
|
284
|
-
if (this.parallaxRaf) cancelAnimationFrame(this.parallaxRaf)
|
|
285
|
-
this.parallaxRaf = null
|
|
286
|
-
},
|
|
287
|
-
scheduleParallaxUpdate() {
|
|
288
|
-
if (!this.parallaxEnabled) return
|
|
289
|
-
if (this.parallaxRaf) return
|
|
290
|
-
this.parallaxRaf = requestAnimationFrame(() => {
|
|
291
|
-
this.parallaxRaf = null
|
|
292
|
-
this.updateParallax()
|
|
293
|
-
})
|
|
294
|
-
},
|
|
295
|
-
updateParallax() {
|
|
296
|
-
const el = this.$refs.header
|
|
297
|
-
if (!el) return
|
|
298
|
-
|
|
299
|
-
const rect = el.getBoundingClientRect()
|
|
300
|
-
const vh = window.innerHeight || 1
|
|
301
|
-
|
|
302
|
-
// Progress through viewport: 0 (below) -> 1 (above)
|
|
303
|
-
// We keep it gentle and clamp
|
|
304
|
-
const mid = rect.top + rect.height * 0.25
|
|
305
|
-
const tRaw = 1 - mid / vh
|
|
306
|
-
const t = Math.max(0, Math.min(1, tRaw * 1.25))
|
|
307
|
-
const t2 = Math.max(0, Math.min(1, tRaw * 1.25)) // field
|
|
308
|
-
const t3 = Math.max(0, Math.min(1, tRaw * 1.6)) // ribbons
|
|
309
|
-
|
|
310
|
-
// Subtle movement only (px)
|
|
311
|
-
const y1 = (t - 0.5) * 22 // base
|
|
312
|
-
const y2 = (t2 - 0.5) * 60 // field
|
|
313
|
-
const y3 = (t3 - 0.5) * 40 // ribbons
|
|
314
|
-
|
|
315
|
-
el.style.setProperty('--secondary-parallax-y1', `${y1}px`)
|
|
316
|
-
el.style.setProperty('--secondary-parallax-y2', `${y2}px`)
|
|
317
|
-
el.style.setProperty('--secondary-parallax-y3', `${y3}px`)
|
|
318
|
-
},
|
|
319
133
|
},
|
|
320
134
|
}
|
|
321
135
|
</script>
|
|
@@ -344,13 +158,14 @@ export default {
|
|
|
344
158
|
}
|
|
345
159
|
|
|
346
160
|
.asd20-secondary-header {
|
|
347
|
-
--secondary-header-image: none;
|
|
348
161
|
position: relative;
|
|
349
162
|
display: flex;
|
|
350
163
|
flex-shrink: 0;
|
|
351
164
|
flex-direction: column;
|
|
352
165
|
color: var(--website-homepage-header__secondary-foreground-color);
|
|
353
|
-
background
|
|
166
|
+
// CommCenter supplies a full background shorthand (image, position, size, repeat).
|
|
167
|
+
background: var(--website-homepage-header__secondary-background-style, none);
|
|
168
|
+
background-color: var(--website-homepage-header__secondary-background-color);
|
|
354
169
|
padding: space(1) 0 0 0;
|
|
355
170
|
|
|
356
171
|
mask: url(#secondary-header-mask-mobile);
|
|
@@ -358,7 +173,6 @@ export default {
|
|
|
358
173
|
mask-size: 100% 100%;
|
|
359
174
|
-webkit-mask-size: 100% 100%;
|
|
360
175
|
|
|
361
|
-
/* Ensure content stays above the parallax layers */
|
|
362
176
|
.asd20-messaging {
|
|
363
177
|
position: relative;
|
|
364
178
|
z-index: 2;
|
|
@@ -367,94 +181,6 @@ export default {
|
|
|
367
181
|
flex-direction: column;
|
|
368
182
|
}
|
|
369
183
|
|
|
370
|
-
/* Parallax background container */
|
|
371
|
-
.secondary-parallax {
|
|
372
|
-
position: absolute;
|
|
373
|
-
inset: 0;
|
|
374
|
-
z-index: 1;
|
|
375
|
-
pointer-events: none;
|
|
376
|
-
overflow: hidden; /* mask will clip, but this avoids any edge artifacts */
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
.secondary-parallax__layer {
|
|
380
|
-
position: absolute;
|
|
381
|
-
inset: -10% -10% -10% -10%;
|
|
382
|
-
transform: translate3d(0, 0, 0);
|
|
383
|
-
will-change: transform;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/* Layer 1: base gradient glow */
|
|
387
|
-
.secondary-parallax__base {
|
|
388
|
-
transform: translate3d(0, var(--secondary-parallax-y1, 0px), 0);
|
|
389
|
-
background: radial-gradient(
|
|
390
|
-
800px 520px at 90% 90%,
|
|
391
|
-
rgba(255, 255, 255, 0.55) 0%,
|
|
392
|
-
rgba(255, 255, 255, 0.22) 0%,
|
|
393
|
-
rgba(255, 255, 255, 0) 0%
|
|
394
|
-
),
|
|
395
|
-
linear-gradient(
|
|
396
|
-
90deg,
|
|
397
|
-
rgba(12, 36, 86, 0.95) 0%,
|
|
398
|
-
rgba(12, 36, 86, 0.85) 35%,
|
|
399
|
-
rgba(12, 36, 86, 0.25) 100%
|
|
400
|
-
);
|
|
401
|
-
/* linear-gradient(*/
|
|
402
|
-
/* 90deg,*/
|
|
403
|
-
/* rgba(12, 36, 86, 0.95) 0%,*/
|
|
404
|
-
/* rgba(24, 74, 160, 0.6) 85%,*/
|
|
405
|
-
/* rgba(112, 160, 230, 0.85) 100%*/
|
|
406
|
-
/* );*/
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/* Layer 2: soft wave fields (broad arcs) */
|
|
410
|
-
.secondary-parallax__field {
|
|
411
|
-
transform: translate3d(0px, var(--secondary-parallax-y2, 0px), 0)
|
|
412
|
-
rotate(-5deg);
|
|
413
|
-
background: radial-gradient(
|
|
414
|
-
280% 155% at 20% 110%,
|
|
415
|
-
rgba(255, 255, 255, 0) 0%,
|
|
416
|
-
rgba(255, 255, 255, 0) 62%,
|
|
417
|
-
rgba(188, 220, 250, 0.95) 70%,
|
|
418
|
-
rgba(255, 255, 255, 0) 72%
|
|
419
|
-
);
|
|
420
|
-
filter: none;
|
|
421
|
-
opacity: 0.9;
|
|
422
|
-
mask-image: linear-gradient(
|
|
423
|
-
90deg,
|
|
424
|
-
rgba(0, 0, 0, 0.85) 0%,
|
|
425
|
-
rgba(0, 0, 0, 1) 85%
|
|
426
|
-
);
|
|
427
|
-
-webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,1) 85%);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/* Layer 3: highlight ribbons (brighter curves) */
|
|
431
|
-
.secondary-parallax__ribbons {
|
|
432
|
-
transform: translate3d(0, var(--secondary-parallax-y3, 0px), 0)
|
|
433
|
-
rotate(-3deg);
|
|
434
|
-
background: radial-gradient(
|
|
435
|
-
260% 160% at 50% 110%,
|
|
436
|
-
rgba(255, 255, 255, 0) 0%,
|
|
437
|
-
rgba(255, 255, 255, 0) 60%,
|
|
438
|
-
rgba(255, 255, 255, 0.9) 64%,
|
|
439
|
-
rgba(255, 255, 255, 0) 70%
|
|
440
|
-
);
|
|
441
|
-
opacity: 0.9;
|
|
442
|
-
filter: none;
|
|
443
|
-
mask-image: linear-gradient(
|
|
444
|
-
90deg,
|
|
445
|
-
rgba(0, 0, 0, 0.3) 0%,
|
|
446
|
-
rgba(0, 0, 0, 1) 70%
|
|
447
|
-
);
|
|
448
|
-
-webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,1) 70%);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/* Reduced motion: lock the layers */
|
|
452
|
-
@media (prefers-reduced-motion: reduce) {
|
|
453
|
-
.secondary-parallax__layer {
|
|
454
|
-
transform: none !important;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
184
|
& :deep(.message-image) {
|
|
459
185
|
order: 2;
|
|
460
186
|
border-top: none !important;
|
|
@@ -484,6 +210,15 @@ export default {
|
|
|
484
210
|
padding: space(1) space(1) space(1) space(1);
|
|
485
211
|
}
|
|
486
212
|
|
|
213
|
+
& :deep(.asd20-messaging__button-group) {
|
|
214
|
+
display: grid;
|
|
215
|
+
grid-template-columns: minmax(0, 1fr);
|
|
216
|
+
gap: space(0.5);
|
|
217
|
+
width: 70vw;
|
|
218
|
+
max-width: 100%;
|
|
219
|
+
margin: space(0.5) auto;
|
|
220
|
+
}
|
|
221
|
+
|
|
487
222
|
& :deep(.asd20-button) {
|
|
488
223
|
@include asd20-font(
|
|
489
224
|
0.75,
|
|
@@ -492,8 +227,10 @@ export default {
|
|
|
492
227
|
700
|
|
493
228
|
);
|
|
494
229
|
flex-direction: column;
|
|
495
|
-
|
|
496
|
-
|
|
230
|
+
box-sizing: border-box;
|
|
231
|
+
min-width: 0;
|
|
232
|
+
width: 100%;
|
|
233
|
+
margin: 0 !important;
|
|
497
234
|
color: var(--website-homepage-header__secondary-button-foreground-color);
|
|
498
235
|
background: var(
|
|
499
236
|
--website-homepage-header__secondary-button-background-color
|
|
@@ -505,6 +242,9 @@ export default {
|
|
|
505
242
|
z-index: 2;
|
|
506
243
|
overflow: hidden;
|
|
507
244
|
}
|
|
245
|
+
& :deep(.asd20-button__label) {
|
|
246
|
+
overflow-wrap: anywhere;
|
|
247
|
+
}
|
|
508
248
|
& :deep(.asd20-button)::before {
|
|
509
249
|
content: '';
|
|
510
250
|
position: absolute;
|
|
@@ -542,9 +282,9 @@ export default {
|
|
|
542
282
|
& :deep(.lead) {
|
|
543
283
|
width: 100%;
|
|
544
284
|
}
|
|
545
|
-
& :deep(.asd20-
|
|
285
|
+
& :deep(.asd20-messaging__button-group) {
|
|
546
286
|
width: 50vw;
|
|
547
|
-
margin:
|
|
287
|
+
margin-inline: 0;
|
|
548
288
|
}
|
|
549
289
|
}
|
|
550
290
|
}
|
|
@@ -575,14 +315,8 @@ export default {
|
|
|
575
315
|
}
|
|
576
316
|
|
|
577
317
|
@media (min-width: 1024px) {
|
|
578
|
-
.asd20-secondary-header
|
|
318
|
+
.asd20-secondary-header {
|
|
579
319
|
padding: space(3) space(3) space(2) space(3);
|
|
580
|
-
background-color: var(--website-homepage-header__secondary-background-color);
|
|
581
|
-
background-image: var(--secondary-header-image);
|
|
582
|
-
background-position: center;
|
|
583
|
-
background-repeat: no-repeat;
|
|
584
|
-
background-size: cover;
|
|
585
|
-
background-attachment: scroll;
|
|
586
320
|
padding-top: 70px;
|
|
587
321
|
|
|
588
322
|
mask: url(#secondary-header-mask-desktop);
|
|
@@ -607,6 +341,11 @@ export default {
|
|
|
607
341
|
border-bottom: none;
|
|
608
342
|
}
|
|
609
343
|
|
|
344
|
+
& :deep(.asd20-messaging__button-group) {
|
|
345
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
|
|
346
|
+
width: 100%;
|
|
347
|
+
}
|
|
348
|
+
|
|
610
349
|
& :deep(.asd20-button) {
|
|
611
350
|
@include asd20-font(
|
|
612
351
|
0.75,
|
|
@@ -615,8 +354,6 @@ export default {
|
|
|
615
354
|
700
|
|
616
355
|
);
|
|
617
356
|
flex-direction: row;
|
|
618
|
-
width: inherit;
|
|
619
|
-
margin: space(0.5) space(0.5) 0 0 !important;
|
|
620
357
|
padding: space(0.5) space(1.5);
|
|
621
358
|
}
|
|
622
359
|
|
|
@@ -634,64 +371,17 @@ export default {
|
|
|
634
371
|
}
|
|
635
372
|
}
|
|
636
373
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
display: none;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
.asd20-secondary-header--parallax-enabled-background {
|
|
647
|
-
background-attachment: fixed;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
.asd20-secondary-header--parallax-enabled-background .secondary-parallax__field,
|
|
651
|
-
.asd20-secondary-header--parallax-enabled-background .secondary-parallax__ribbons {
|
|
652
|
-
display: block;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
.asd20-secondary-header--parallax-enabled-background .secondary-parallax__field {
|
|
656
|
-
transform: translate3d(0px, var(--secondary-parallax-y2, 0px), 0)
|
|
657
|
-
rotate(-5deg);
|
|
658
|
-
filter: none;
|
|
659
|
-
opacity: 0.9;
|
|
660
|
-
mask-image: linear-gradient(
|
|
661
|
-
90deg,
|
|
662
|
-
rgba(0, 0, 0, 0.85) 0%,
|
|
663
|
-
rgba(0, 0, 0, 1) 85%
|
|
664
|
-
);
|
|
665
|
-
-webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,1) 85%);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
.asd20-secondary-header--parallax-enabled-background .secondary-parallax__ribbons {
|
|
669
|
-
transform: translate3d(0, var(--secondary-parallax-y3, 0px), 0)
|
|
670
|
-
rotate(-3deg);
|
|
671
|
-
background: radial-gradient(
|
|
672
|
-
180% 160% at 40% 110%,
|
|
673
|
-
rgba(255, 255, 255, 0) 0%,
|
|
674
|
-
rgba(255, 255, 255, 0) 60%,
|
|
675
|
-
rgba(255, 255, 255, 0.9) 64%,
|
|
676
|
-
rgba(255, 255, 255, 0) 70%
|
|
677
|
-
);
|
|
678
|
-
opacity: 0.9;
|
|
679
|
-
filter: none;
|
|
680
|
-
mask-image: linear-gradient(
|
|
681
|
-
90deg,
|
|
682
|
-
rgba(0, 0, 0, 0.3) 0%,
|
|
683
|
-
rgba(0, 0, 0, 1) 70%
|
|
684
|
-
);
|
|
685
|
-
-webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,1) 70%);
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
.asd20-secondary-header--desktop-background.asd20-secondary-header--hide-desktop-image {
|
|
689
|
-
& :deep(.asd20-messaging--fullscreen > .message-image) {
|
|
690
|
-
display: none;
|
|
374
|
+
}
|
|
375
|
+
@media (min-width: 1025px) {
|
|
376
|
+
.asd20-secondary-header {
|
|
377
|
+
& :deep(.asd20-messaging__button-group) {
|
|
378
|
+
display: flex;
|
|
379
|
+
flex-wrap: wrap;
|
|
691
380
|
}
|
|
692
381
|
|
|
693
|
-
& :deep(.asd20-
|
|
694
|
-
|
|
382
|
+
& :deep(.asd20-button) {
|
|
383
|
+
width: fit-content;
|
|
384
|
+
max-width: 100%;
|
|
695
385
|
}
|
|
696
386
|
}
|
|
697
387
|
}
|
|
@@ -210,6 +210,7 @@
|
|
|
210
210
|
|
|
211
211
|
<asd20-media-section
|
|
212
212
|
v-if="combinedMessageImages.length > 1 || combinedMessageVideos.length"
|
|
213
|
+
:body-messages="[...primaryMessages, ...secondaryMessages]"
|
|
213
214
|
:images="combinedMessageImages || []"
|
|
214
215
|
:videos="combinedMessageVideos || []"
|
|
215
216
|
>
|
|
@@ -211,6 +211,7 @@
|
|
|
211
211
|
|
|
212
212
|
<asd20-media-section
|
|
213
213
|
v-if="combinedMessageImages.length > 1 || combinedMessageVideos.length"
|
|
214
|
+
:body-messages="[...primaryMessages, ...secondaryMessages]"
|
|
214
215
|
:images="combinedMessageImages || []"
|
|
215
216
|
:videos="combinedMessageVideos || []"
|
|
216
217
|
>
|
|
@@ -230,6 +230,7 @@
|
|
|
230
230
|
|
|
231
231
|
<asd20-media-section
|
|
232
232
|
v-if="combinedMessageImages.length > 1 || combinedMessageVideos.length"
|
|
233
|
+
:body-messages="[...primaryMessages, ...secondaryMessages]"
|
|
233
234
|
:images="combinedMessageImages || []"
|
|
234
235
|
:videos="combinedMessageVideos || []"
|
|
235
236
|
>
|
|
@@ -95,9 +95,10 @@
|
|
|
95
95
|
></asd20-feeds-section> -->
|
|
96
96
|
|
|
97
97
|
<asd20-media-section
|
|
98
|
-
v-if="
|
|
98
|
+
v-if="combinedMessageImages.length || combinedMessageVideos.length"
|
|
99
|
+
:body-messages="[...primaryDetailMessages, ...secondaryMessages]"
|
|
99
100
|
allow-single-image-gallery
|
|
100
|
-
:images="
|
|
101
|
+
:images="combinedMessageImages || []"
|
|
101
102
|
:videos="combinedMessageVideos || []"
|
|
102
103
|
>
|
|
103
104
|
</asd20-media-section>
|
|
@@ -222,6 +222,7 @@
|
|
|
222
222
|
|
|
223
223
|
<asd20-media-section
|
|
224
224
|
v-if="combinedMessageImages.length > 1 || combinedMessageVideos.length"
|
|
225
|
+
:body-messages="[...primaryMessages, ...secondaryMessages]"
|
|
225
226
|
:images="combinedMessageImages || []"
|
|
226
227
|
:videos="combinedMessageVideos || []"
|
|
227
228
|
>
|
|
@@ -276,6 +276,7 @@
|
|
|
276
276
|
|
|
277
277
|
<asd20-media-section
|
|
278
278
|
v-if="combinedMessageImages.length > 1 || combinedMessageVideos.length"
|
|
279
|
+
:body-messages="[...primaryMessages, ...secondaryMessages]"
|
|
279
280
|
:images="combinedMessageImages || []"
|
|
280
281
|
:videos="combinedMessageVideos || []"
|
|
281
282
|
>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { parseFragment } from 'parse5'
|
|
2
|
+
import { buildRichBodyRenderModel } from '../components/atoms/Asd20RichBodyContent/messageDocumentRenderer'
|
|
3
|
+
|
|
4
|
+
const STORAGE_HOST = 'asd20websitestorage.blob.core.windows.net'
|
|
5
|
+
const RELATIVE_ORIGIN = 'https://ui-next.invalid'
|
|
6
|
+
|
|
7
|
+
function resourceKey(value) {
|
|
8
|
+
if (typeof value !== 'string' || !value.trim()) return ''
|
|
9
|
+
try {
|
|
10
|
+
const url = new URL(value.trim(), RELATIVE_ORIGIN)
|
|
11
|
+
if (!['http:', 'https:'].includes(url.protocol)) return ''
|
|
12
|
+
url.hash = ''
|
|
13
|
+
// The website media proxy and blob origin serve the same stored files.
|
|
14
|
+
if (url.pathname.startsWith('/_media/')) {
|
|
15
|
+
return `storage:${url.pathname.slice('/_media'.length)}${url.search}`
|
|
16
|
+
}
|
|
17
|
+
if (url.hostname === STORAGE_HOST) {
|
|
18
|
+
return `storage:${url.pathname}${url.search}`
|
|
19
|
+
}
|
|
20
|
+
return url.href
|
|
21
|
+
} catch {
|
|
22
|
+
return ''
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function videoKey(value) {
|
|
27
|
+
const key = resourceKey(value)
|
|
28
|
+
if (!key || key.startsWith('storage:')) return key
|
|
29
|
+
const url = new URL(key)
|
|
30
|
+
const host = url.hostname.replace(/^www\./, '')
|
|
31
|
+
if (['youtube.com', 'youtube-nocookie.com', 'youtu.be'].includes(host)) {
|
|
32
|
+
const id = host === 'youtu.be'
|
|
33
|
+
? url.pathname.split('/')[1]
|
|
34
|
+
: url.searchParams.get('v') || url.pathname.match(/^\/(?:embed|shorts)\/([^/]+)/)?.[1]
|
|
35
|
+
if (id) return `youtube:${id}`
|
|
36
|
+
}
|
|
37
|
+
if (['vimeo.com', 'player.vimeo.com'].includes(host)) {
|
|
38
|
+
const id = url.pathname.match(/^\/(?:video\/)?(\d+)(?:\/|$)/)?.[1]
|
|
39
|
+
if (id) return `vimeo:${id}`
|
|
40
|
+
}
|
|
41
|
+
if (host === 'live.myvrspot.com' && url.searchParams.get('v')) {
|
|
42
|
+
return `myvrspot:${url.searchParams.get('v')}`
|
|
43
|
+
}
|
|
44
|
+
return key
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function addSource(sources, value, normalize) {
|
|
48
|
+
const key = normalize(value)
|
|
49
|
+
if (key) sources.add(key)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function collectHtmlMedia(html, sources) {
|
|
53
|
+
const visit = node => {
|
|
54
|
+
const attrs = Object.fromEntries((node.attrs || []).map(attr => [attr.name, attr.value]))
|
|
55
|
+
if (node.tagName === 'img') {
|
|
56
|
+
addSource(sources.images, attrs.src, resourceKey)
|
|
57
|
+
}
|
|
58
|
+
if (['iframe', 'video'].includes(node.tagName) ||
|
|
59
|
+
(node.tagName === 'source' && node.parentNode?.tagName === 'video')) {
|
|
60
|
+
addSource(sources.videos, attrs.src, videoKey)
|
|
61
|
+
}
|
|
62
|
+
for (const child of node.childNodes || []) visit(child)
|
|
63
|
+
}
|
|
64
|
+
visit(parseFragment(html || ''))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default function excludeBodyMedia({ images = [], videos = [], bodyMessages = [] } = {}) {
|
|
68
|
+
const sources = { images: new Set(), videos: new Set() }
|
|
69
|
+
for (const message of bodyMessages) {
|
|
70
|
+
if (!message) continue
|
|
71
|
+
// Use the renderer's selected content, including its HTML fallback for
|
|
72
|
+
// invalid/unsupported JSON, rather than inspecting stale saved sidecars.
|
|
73
|
+
const model = buildRichBodyRenderModel({
|
|
74
|
+
bodyContent: message.bodyContent || message.bodyHtml || '',
|
|
75
|
+
bodyJson: message.bodyJson,
|
|
76
|
+
})
|
|
77
|
+
for (const node of model.nodes) {
|
|
78
|
+
if (node.html) collectHtmlMedia(node.html, sources)
|
|
79
|
+
if (node.type === 'accordion') {
|
|
80
|
+
for (const item of node.block.items || []) {
|
|
81
|
+
if (item.contentType !== 'tableau') collectHtmlMedia(item.bodyHtml, sources)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
images: images.filter(image => image && ![
|
|
89
|
+
image.url,
|
|
90
|
+
...(image.files || []).map(file => file?.url),
|
|
91
|
+
].some(url => sources.images.has(resourceKey(url)))),
|
|
92
|
+
videos: videos.filter(video => video && ![
|
|
93
|
+
video.embedUrl, video.watchUrl, video.url,
|
|
94
|
+
].some(url => sources.videos.has(videoKey(url)))),
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -1,32 +1,6 @@
|
|
|
1
1
|
import responsiveBreakpointMixin from './responsiveBreakpointMixin'
|
|
2
2
|
import { buildBreadcrumbLinks } from '../helpers/breadcrumbLinks'
|
|
3
3
|
|
|
4
|
-
function getMessageBodyHtml(message) {
|
|
5
|
-
return (message && (message.bodyContent || message.bodyHtml)) || ''
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function getImageUrls(image) {
|
|
9
|
-
const urls = []
|
|
10
|
-
const files = (image && image.files) || []
|
|
11
|
-
if (image && image.url) urls.push(image.url)
|
|
12
|
-
files.forEach(file => {
|
|
13
|
-
if (file && file.url) urls.push(file.url)
|
|
14
|
-
})
|
|
15
|
-
return urls
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function normalizeHtmlValue(value) {
|
|
19
|
-
return String(value || '').replace(/&/g, '&')
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function imageAppearsInBody(image, bodyHtml) {
|
|
23
|
-
if (!bodyHtml) return false
|
|
24
|
-
const normalizedBodyHtml = normalizeHtmlValue(bodyHtml)
|
|
25
|
-
return getImageUrls(image).some(url =>
|
|
26
|
-
normalizedBodyHtml.includes(normalizeHtmlValue(url))
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
4
|
export default {
|
|
31
5
|
mixins: [responsiveBreakpointMixin],
|
|
32
6
|
|
|
@@ -270,24 +244,6 @@ export default {
|
|
|
270
244
|
}, [])
|
|
271
245
|
},
|
|
272
246
|
|
|
273
|
-
articleGalleryImages() {
|
|
274
|
-
const messageBodies = (this.primaryDetailMessages || [])
|
|
275
|
-
.map(getMessageBodyHtml)
|
|
276
|
-
.filter(Boolean)
|
|
277
|
-
|
|
278
|
-
return this.combinedMessageImages.filter(image => {
|
|
279
|
-
if (!image || image.isCover) return false
|
|
280
|
-
return !messageBodies.some(bodyHtml => imageAppearsInBody(image, bodyHtml))
|
|
281
|
-
})
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
shouldShowArticleMediaSection() {
|
|
285
|
-
return (
|
|
286
|
-
this.articleGalleryImages.length > 0 ||
|
|
287
|
-
this.combinedMessageVideos.length > 0
|
|
288
|
-
)
|
|
289
|
-
},
|
|
290
|
-
|
|
291
247
|
combinedMessageVideos() {
|
|
292
248
|
return (this.messages || []).reduce((a, m) => {
|
|
293
249
|
const videos = m.videos || []
|