@playpilot/tpi 5.11.0-beta.participants.2 → 5.11.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 (30) hide show
  1. package/dist/link-injections.js +10 -11
  2. package/package.json +1 -1
  3. package/src/lib/fakeData.ts +0 -70
  4. package/src/lib/linkInjection.ts +29 -11
  5. package/src/lib/playlink.ts +1 -4
  6. package/src/lib/types/title.d.ts +0 -2
  7. package/src/routes/+page.svelte +0 -1
  8. package/src/routes/components/Ads/Disclaimer.svelte +83 -0
  9. package/src/routes/components/Ads/Display.svelte +22 -7
  10. package/src/routes/components/Ads/TopScroll.svelte +2 -64
  11. package/src/routes/components/Icons/IconClose.svelte +1 -1
  12. package/src/routes/components/Modal.svelte +7 -41
  13. package/src/routes/components/Playlink.svelte +7 -1
  14. package/src/routes/components/Playlinks.svelte +4 -2
  15. package/src/routes/components/Title.svelte +2 -8
  16. package/src/routes/components/TitleModal.svelte +3 -2
  17. package/src/tests/routes/components/Ads/Disclaimer.test.js +20 -0
  18. package/src/tests/routes/components/Ads/Display.test.js +9 -2
  19. package/src/tests/routes/components/Ads/TopScroll.test.js +8 -10
  20. package/src/tests/routes/components/Playlink.test.js +14 -0
  21. package/src/lib/modal.ts +0 -77
  22. package/src/lib/types/participant.d.ts +0 -14
  23. package/src/routes/components/Icons/IconArrow.svelte +0 -17
  24. package/src/routes/components/ListTitle.svelte +0 -169
  25. package/src/routes/components/Participant.svelte +0 -88
  26. package/src/routes/components/ParticipantModal.svelte +0 -30
  27. package/src/routes/components/Participants.svelte +0 -79
  28. package/src/routes/components/PlaylinkIcon.svelte +0 -40
  29. package/src/routes/components/Tabs.svelte +0 -47
  30. package/src/tests/routes/components/Participants.test.js +0 -41
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "5.11.0-beta.participants.2",
3
+ "version": "5.11.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -1,5 +1,4 @@
1
1
  import type { LinkInjection } from "./types/injection"
2
- import type { ParticipantData } from "./types/participant"
3
2
  import type { TitleData } from "./types/title"
4
3
 
5
4
  export const title: TitleData = {
@@ -70,72 +69,3 @@ export const linkInjections: LinkInjection[] = [{
70
69
  playpilot_url: 'https://playpilot.com/movie/example-4/',
71
70
  key: 'some-key-4',
72
71
  }]
73
-
74
- export const participants: ParticipantData[] = [
75
- {
76
- sid: 'pr5C5W',
77
- name: 'James Franco',
78
- birth_date: '1978-04-19',
79
- death_date: null,
80
- jobs: ['actor'],
81
- image: null,
82
- image_uuid: null,
83
- gender: 'Male',
84
- character: 'Will Rodman (archive footage) (uncredited)',
85
- },
86
- {
87
- sid: 'pr8bZm',
88
- name: 'Thomas Rosales Jr.',
89
- birth_date: '1948-02-03',
90
- death_date: null,
91
- jobs: ['actor'],
92
- image: null,
93
- image_uuid: null,
94
- gender: 'Male',
95
- character: 'Old Man',
96
- },
97
- {
98
- sid: 'pr45Dp',
99
- name: 'Barack Obama',
100
- birth_date: '1961-08-04',
101
- death_date: null,
102
- jobs: ['actor'],
103
- image: null,
104
- image_uuid: null,
105
- gender: 'Male',
106
- character: 'Self (archive footage) (uncredited)',
107
- },
108
- {
109
- sid: 'pr6DnN',
110
- name: 'Gary Oldman',
111
- birth_date: '1958-03-21',
112
- death_date: null,
113
- jobs: ['actor'],
114
- image: null,
115
- image_uuid: null,
116
- gender: 'Male',
117
- character: 'Dreyfus',
118
- },
119
- {
120
- sid: 'pr7GK8',
121
- name: 'Michael Papajohn',
122
- birth_date: '1964-11-07',
123
- death_date: null,
124
- jobs: ['actor'],
125
- image: null,
126
- image_uuid: null,
127
- gender: 'Male',
128
- character: 'Cannon-Gunner',
129
- },
130
- {
131
- sid: 'pr88KG',
132
- name: 'Judy Greer',
133
- birth_date: '1975-07-20',
134
- death_date: null,
135
- jobs: ['actor'],
136
- image: null,
137
- image_uuid: null,
138
- gender: 'Female',
139
- character: 'Cornelia',
140
- },
141
- ]
@@ -1,4 +1,5 @@
1
1
  import { mount, unmount } from 'svelte'
2
+ import TitleModal from '../routes/components/TitleModal.svelte'
2
3
  import TitlePopover from '../routes/components/TitlePopover.svelte'
3
4
  import AfterArticlePlaylinks from '../routes/components/AfterArticlePlaylinks.svelte'
4
5
  import { cleanPhrase, findNumberOfMatchesInString, findShortestMatchBetweenPhrases, findTextNodeContaining, getIndexOfPhraseInElement, getNumberOfLeadingAndTrailingSpaces, isNodeInLink, replaceBetween, replaceStartingFrom } from './text'
@@ -8,7 +9,6 @@ import { playFallbackViewTransition } from './viewTransition'
8
9
  import { prefersReducedMotion } from 'svelte/motion'
9
10
  import { getNumberOfOccurrencesInArray } from './array'
10
11
  import { mobileBreakpoint } from './constants'
11
- import { destroyAllModals, openModal } from './modal'
12
12
 
13
13
  const keyDataAttribute = 'data-playpilot-injection-key'
14
14
  const keySelector = `[${keyDataAttribute}]`
@@ -16,6 +16,7 @@ const keySelector = `[${keyDataAttribute}]`
16
16
  let currentlyHoveredInjection: EventTarget | null = null
17
17
  let activePopoverInsertedComponent: object | null = null
18
18
  let afterArticlePlaylinkInsertedComponent: object | null = null
19
+ let activeModalInsertedComponent: object | null = null
19
20
 
20
21
  /**
21
22
  * Return a list of all valid text containing elements that may get injected into.
@@ -347,7 +348,7 @@ function addLinkInjectionEventListeners(injections: LinkInjection[]): void {
347
348
 
348
349
  playFallbackViewTransition(() => {
349
350
  destroyLinkPopover(false)
350
- openModal({ event, injection, data: injection.title_details })
351
+ openLinkModal(event, injection)
351
352
  }, !prefersReducedMotion.current && window.innerWidth >= mobileBreakpoint && !window.matchMedia("(pointer: coarse)").matches)
352
353
  })
353
354
 
@@ -379,6 +380,29 @@ function addLinkInjectionEventListeners(injections: LinkInjection[]): void {
379
380
  })
380
381
  }
381
382
 
383
+ /**
384
+ * Open modal for the corresponding injection by mounting the component and saving it to a variable.
385
+ * Ignore clicks that used modifier keys or that were not left click.
386
+ */
387
+ function openLinkModal(event: MouseEvent, injection: LinkInjection): void {
388
+ if (isHoldingSpecialKey(event)) return
389
+ if (activeModalInsertedComponent) return
390
+
391
+ event.preventDefault()
392
+
393
+ activeModalInsertedComponent = mount(TitleModal, { target: getPlayPilotWrapperElement(), props: { title: injection.title_details!, onclose: destroyLinkModal } })
394
+ }
395
+
396
+ /**
397
+ * Unmount the modal, removing it from the dom
398
+ */
399
+ function destroyLinkModal(outro: boolean = true): void {
400
+ if (!activeModalInsertedComponent) return
401
+
402
+ unmount(activeModalInsertedComponent, { outro })
403
+ activeModalInsertedComponent = null
404
+ }
405
+
382
406
  /**
383
407
  * When a link is hovered, it is shown as a popover. The component is mounted when a mouse enters the link,
384
408
  * and removed when clicked or on mouseleave.
@@ -436,13 +460,7 @@ export function insertAfterArticlePlaylinks(elements: HTMLElement[], injections:
436
460
  target.dataset.playpilotAfterArticlePlaylinks = 'true'
437
461
  insertElement.insertAdjacentElement(insertPosition, target)
438
462
 
439
- afterArticlePlaylinkInsertedComponent = mount(AfterArticlePlaylinks, {
440
- target,
441
- props: {
442
- linkInjections: injections,
443
- onclickmodal: (event, injection) => openModal({ event, injection, data: injection.title_details })
444
- }
445
- })
463
+ afterArticlePlaylinkInsertedComponent = mount(AfterArticlePlaylinks, { target, props: { linkInjections: injections, onclickmodal: (event, injection) => openLinkModal(event, injection) } })
446
464
  }
447
465
 
448
466
  function clearAfterArticlePlaylinks(): void {
@@ -461,7 +479,7 @@ export function clearLinkInjections(): void {
461
479
  elements.forEach((element) => clearLinkInjection(element.getAttribute(keyDataAttribute) || ''))
462
480
 
463
481
  clearAfterArticlePlaylinks()
464
- destroyAllModals(false)
482
+ destroyLinkModal(false)
465
483
  destroyLinkPopover(false)
466
484
  }
467
485
 
@@ -568,6 +586,6 @@ export function isEquivalentInjection(injection1: LinkInjection, injection2: Lin
568
586
  return injection1.title === injection2.title && cleanPhrase(injection1.sentence) === cleanPhrase(injection2.sentence)
569
587
  }
570
588
 
571
- export function getPlayPilotWrapperElement(): Element {
589
+ function getPlayPilotWrapperElement(): Element {
572
590
  return document.querySelector('[data-playpilot-link-injections]') || document.body
573
591
  }
@@ -2,14 +2,11 @@ import type { PlaylinkData } from "./types/playlink"
2
2
 
3
3
  /**
4
4
  * Merge playlinks of the same provider of BUY and RENT categories into a shared TVOD category.
5
- * Also remove playlinks without logos, as these are likely sub providers.
6
5
  */
7
6
  export function mergePlaylinks(playlinks: PlaylinkData[]): PlaylinkData[] {
8
- const filtered = playlinks.filter(playlink => !!playlink.logo_url)
9
-
10
7
  let merged: PlaylinkData[] = []
11
8
 
12
- for (const playlink of filtered) {
9
+ for (const playlink of playlinks) {
13
10
  let newPlaylink = playlink
14
11
  const existingPlaylink = merged.find(p => p.name === newPlaylink.name)
15
12
 
@@ -1,4 +1,3 @@
1
- import type { ParticipantData } from "./participant"
2
1
  import type { PlaylinkData } from "./playlink"
3
2
 
4
3
  export type TitleData = {
@@ -19,5 +18,4 @@ export type TitleData = {
19
18
  original_title: string
20
19
  length?: number
21
20
  blurb?: string
22
- participants?: ParticipantData[]
23
21
  }
@@ -14,7 +14,6 @@
14
14
  import TrackingPixels from './components/TrackingPixels.svelte'
15
15
  import Debugger from './components/Debugger.svelte'
16
16
  import { fetchAds } from '$lib/ads'
17
- import ParticipantModal from './components/ParticipantModal.svelte';
18
17
 
19
18
  let parentElement: HTMLElement | null = $state(null)
20
19
  let elements: HTMLElement[] = $state([])
@@ -0,0 +1,83 @@
1
+ <script lang="ts">
2
+ import { fade } from 'svelte/transition'
3
+
4
+ interface Props {
5
+ disclaimer: string
6
+ small?: boolean
7
+ }
8
+
9
+ const { disclaimer, small = false }: Props = $props()
10
+
11
+ let tooltipVisible = $state(false)
12
+
13
+ function toggleTooltip(event: MouseEvent): void {
14
+ event.preventDefault()
15
+ event.stopPropagation()
16
+
17
+ tooltipVisible = !tooltipVisible
18
+ }
19
+ </script>
20
+
21
+ <button class="tooltip" onclick={toggleTooltip} data-testid="disclaimer">
22
+ <div class="disclaimer" class:small aria-label="Disclaimer">i</div>
23
+
24
+ {#if tooltipVisible}
25
+ <div class="tooltip-content" transition:fade={{ duration: 50 }} role="paragraph">
26
+ {disclaimer}
27
+ </div>
28
+ {/if}
29
+ </button>
30
+
31
+ <style lang="scss">
32
+ .disclaimer {
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ border: var(--playpilot-disclaimer-border, 2px solid rgba(255, 255, 255, 0.5));
37
+ padding: margin(0.25);
38
+ height: margin(1.25);
39
+ width: margin(1.25);
40
+ border-radius: 99px;
41
+ color: var(--playpilot-disclaimer-text-color, rgba(255, 255, 255, 0.75));
42
+ font-weight: bold;
43
+ line-height: 1;
44
+
45
+ &:hover {
46
+ border-color: var(--playpilot-disclaimer-hover-border-color, white);
47
+ color: var(--playpilot-disclaimer-hover-text-color, white);
48
+ }
49
+
50
+ &.small {
51
+ height: margin(1);
52
+ width: margin(1);
53
+ }
54
+ }
55
+
56
+ .tooltip {
57
+ z-index: 2;
58
+ position: absolute;
59
+ right: 0;
60
+ bottom: 0;
61
+ padding: margin(0.25);
62
+ background: transparent;
63
+ border: 0;
64
+ color: var(--playpilot-disclaimer-tooltip-text-color, var(--playpilot-detail-text-color, white));
65
+ cursor: pointer;
66
+ }
67
+
68
+ .tooltip-content {
69
+ display: block;
70
+ z-index: 20;
71
+ position: absolute;
72
+ right: 100%;
73
+ bottom: margin(0.25);
74
+ width: calc(var(--width, 15rem) * 0.8);
75
+ padding: margin(0.5);
76
+ border-radius: margin(0.5);
77
+ background: var(--playpilot-disclaimer-tooltip-background, var(--playpilot-detail-background, var(--playpilot-content)));
78
+ box-shadow: var(--playpilot-shadow);
79
+ line-height: 1.1;
80
+ text-align: right;
81
+ white-space: normal;
82
+ }
83
+ </style>
@@ -4,6 +4,7 @@
4
4
  import { track } from '$lib/tracking'
5
5
  import type { Campaign } from '$lib/types/campaign'
6
6
  import Tooltip from '../Tooltip.svelte'
7
+ import Disclaimer from './Disclaimer.svelte'
7
8
 
8
9
  interface Props {
9
10
  campaign: Campaign
@@ -14,7 +15,9 @@
14
15
 
15
16
  const { disclaimer, content, cta, campaign_type } = $derived(campaign)
16
17
  const { header, subheader, header_logo: logo, image, video } = $derived(content)
17
- const { header: buttonLabel, url: href } = $derived(cta)
18
+ const { header: buttonLabel, url: href, subheader: info } = $derived(cta)
19
+
20
+ let contentHeight = $state(0)
18
21
 
19
22
  track(TrackingEvent.DisplayAdView, null, { campaign_name: campaign.campaign_name })
20
23
 
@@ -24,24 +27,24 @@
24
27
  </script>
25
28
 
26
29
  <a {href} target="_blank" class="display" class:compact rel="sponsored" {onclick} use:middlemouse={{ onclick }}>
27
- {#if disclaimer}
28
- <div class="disclaimer">
30
+ {#if info}
31
+ <div class="info">
29
32
  {#if compact}
30
33
  <Tooltip>
31
34
  Ad
32
35
 
33
36
  {#snippet content()}
34
- {disclaimer}
37
+ {info}
35
38
  {/snippet}
36
39
  </Tooltip>
37
40
  {:else}
38
- {disclaimer}
41
+ {info}
39
42
  {/if}
40
43
  </div>
41
44
  {/if}
42
45
 
43
46
  {#if logo || header || subheader || buttonLabel}
44
- <div class="cta">
47
+ <div class="cta" bind:clientHeight={contentHeight}>
45
48
  {#if logo}
46
49
  <img class="logo" src={logo} alt="" height="40" width="40" />
47
50
  {/if}
@@ -70,6 +73,12 @@
70
73
  <track kind="captions" />
71
74
  </video>
72
75
  {/if}
76
+
77
+ {#if disclaimer}
78
+ <div class="disclaimer" style:--offset="{contentHeight}px">
79
+ <Disclaimer {disclaimer} />
80
+ </div>
81
+ {/if}
73
82
  </a>
74
83
 
75
84
  <style lang="scss">
@@ -87,7 +96,7 @@
87
96
  font-style: normal !important;
88
97
  }
89
98
 
90
- .disclaimer {
99
+ .info {
91
100
  position: absolute;
92
101
  top: 0;
93
102
  left: 0;
@@ -160,4 +169,10 @@
160
169
  width: 100%;
161
170
  height: auto;
162
171
  }
172
+
173
+ .disclaimer {
174
+ position: absolute;
175
+ bottom: calc(var(--offset) + margin(0.25));
176
+ right: margin(0.25);
177
+ }
163
178
  </style>
@@ -7,7 +7,7 @@
7
7
  import { isInSplitTestVariant, trackSplitTestView } from '$lib/splitTest'
8
8
  import { track } from '$lib/tracking'
9
9
  import type { Campaign } from '$lib/types/campaign'
10
- import { fade } from 'svelte/transition'
10
+ import Disclaimer from './Disclaimer.svelte'
11
11
 
12
12
  interface Props {
13
13
  campaign: Campaign
@@ -29,18 +29,10 @@
29
29
  const contentImage = $derived(imageFromUUID(backgroundImageUUID, ImageDimensions.TopScrollContent))
30
30
 
31
31
  let clientWidth = $state(0)
32
- let tooltipVisible = $state(false)
33
32
 
34
33
  function onclick(): void {
35
34
  track(TrackingEvent.TopScrollClick, null, { campaign_name: campaign.campaign_name })
36
35
  }
37
-
38
- function toggleTooltip(event: MouseEvent): void {
39
- event.preventDefault()
40
- event.stopPropagation()
41
-
42
- tooltipVisible = !tooltipVisible
43
- }
44
36
  </script>
45
37
 
46
38
  <a
@@ -77,15 +69,7 @@
77
69
  {/if}
78
70
 
79
71
  {#if disclaimer}
80
- <button class="tooltip" onclick={toggleTooltip}>
81
- <div class="disclaimer">i</div>
82
-
83
- {#if tooltipVisible}
84
- <div class="tooltip-content" transition:fade={{ duration: 50 }}>
85
- {disclaimer}
86
- </div>
87
- {/if}
88
- </button>
72
+ <Disclaimer {disclaimer} />
89
73
  {/if}
90
74
  {/if}
91
75
  </a>
@@ -198,50 +182,4 @@
198
182
  border-radius: $border-radius-size $border-radius-size 0 0;
199
183
  }
200
184
  }
201
-
202
- .disclaimer {
203
- display: flex;
204
- align-items: center;
205
- justify-content: center;
206
- border: var(--playpilot-top-scroll-disclaimer-border, 2px solid rgba(255, 255, 255, 0.5));
207
- padding: margin(0.25);
208
- height: margin(1.25);
209
- width: margin(1.25);
210
- border-radius: 99px;
211
- color: var(--playpilot-top-scroll-disclaimer-text-color, rgba(255, 255, 255, 0.75));
212
- font-weight: bold;
213
- line-height: 1;
214
-
215
- &:hover {
216
- border-color: var(--playpilot-top-scroll-disclaimer-hover-border-color, white);
217
- color: var(--playpilot-top-scroll-disclaimer-hover-text-color, white);
218
- }
219
- }
220
-
221
- .tooltip {
222
- z-index: 2;
223
- position: absolute;
224
- right: 0;
225
- bottom: 0;
226
- padding: margin(0.25);
227
- background: transparent;
228
- border: 0;
229
- color: var(--playpilot-top-scroll-text-color, white);
230
- cursor: pointer;
231
- }
232
-
233
- .tooltip-content {
234
- display: block;
235
- z-index: 20;
236
- position: absolute;
237
- right: 100%;
238
- bottom: margin(0.25);
239
- width: calc(var(--width) * 0.8);
240
- padding: margin(0.5);
241
- border-radius: margin(1);
242
- background: var(--playpilot-content);
243
- box-shadow: var(--playpilot-shadow);
244
- line-height: 1.1;
245
- text-align: right;
246
- }
247
185
  </style>
@@ -1,3 +1,3 @@
1
1
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
2
- <path d="M14 2L2 14M2 2L14 14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2
+ <path d="M14 2L2 14M2 2L14 14" stroke="currentColor" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/>
3
3
  </svg>
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { fade, fly, scale, type TransitionConfig } from 'svelte/transition'
3
3
  import IconClose from './Icons/IconClose.svelte'
4
- import IconArrow from './Icons/IconArrow.svelte'
5
4
  import RoundButton from './RoundButton.svelte'
6
5
  import DragHandle from './DragHandle.svelte'
7
6
  import { onMount, setContext, type Snippet } from 'svelte'
@@ -9,32 +8,23 @@
9
8
  import { isInSplitTestVariant } from '$lib/splitTest'
10
9
  import { SplitTest } from '$lib/enums/SplitTest'
11
10
  import { mobileBreakpoint } from '$lib/constants'
12
- import { destroyAllModals, getPreviousModal, goBackToPreviousModal } from '$lib/modal'
13
11
 
14
12
  interface Props {
15
13
  children: Snippet
16
14
  bubble?: Snippet | null
17
15
  prepend?: Snippet | null
18
16
  tall?: boolean
19
- closeButtonStyle?: 'shadow' | 'flat'
17
+ onclose?: () => void
20
18
  onscroll?: () => void
21
19
  }
22
20
 
23
- const {
24
- children,
25
- bubble,
26
- prepend,
27
- tall = false,
28
- closeButtonStyle = 'shadow',
29
- onscroll = () => null,
30
- }: Props = $props()
21
+ const { children, bubble, prepend, tall = false, onclose = () => null, onscroll = () => null }: Props = $props()
31
22
 
32
23
  const inlineBubble = isInSplitTestVariant(SplitTest.TopScrollFormat, 1)
33
24
 
34
25
  let windowWidth = $state(0)
35
26
  let dialogElement: HTMLElement | null = $state(null)
36
27
  let dialogOffset: number = $state(0)
37
- let hasPreviousModal = $state(false)
38
28
 
39
29
  const isMobile = $derived(windowWidth < mobileBreakpoint)
40
30
 
@@ -47,8 +37,6 @@
47
37
  const baseOverflowStyle = document.body.style.overflowY
48
38
  document.body.style.overflowY = 'hidden'
49
39
 
50
- hasPreviousModal = !!getPreviousModal()
51
-
52
40
  return () => document.body.style.overflowY = baseOverflowStyle || ''
53
41
  })
54
42
 
@@ -60,7 +48,7 @@
60
48
  }
61
49
  </script>
62
50
 
63
- <svelte:window onkeydown={({ key }) => { if (key === 'Escape') destroyAllModals() }} bind:innerWidth={windowWidth} />
51
+ <svelte:window onkeydown={({ key }) => { if (key === 'Escape') onclose() }} bind:innerWidth={windowWidth} />
64
52
 
65
53
  <div class="modal" style:--dialog-offset="{dialogOffset}px" transition:fade|global={{ duration: 150 }} class:has-bubble={!!bubble && inlineBubble} class:has-prepend={!!prepend}>
66
54
  {#if prepend}
@@ -77,21 +65,13 @@
77
65
 
78
66
  {#if isMobile}
79
67
  <div class="drag-handle" transition:scaleOrFly|global>
80
- <DragHandle target={dialogElement!} onpassed={() => destroyAllModals()} />
68
+ <DragHandle target={dialogElement!} onpassed={() => onclose()} />
81
69
  </div>
82
70
  {/if}
83
71
 
84
72
  <div class="dialog" class:tall {onscroll} bind:this={dialogElement} role="dialog" aria-labelledby="title" transition:scaleOrFly|global={{ y: window.innerHeight }} data-view-transition-new>
85
- {#if hasPreviousModal}
86
- <div class="close back {closeButtonStyle}">
87
- <RoundButton onclick={() => goBackToPreviousModal()}>
88
- <IconArrow direction="left" />
89
- </RoundButton>
90
- </div>
91
- {/if}
92
-
93
- <div class="close {closeButtonStyle}">
94
- <RoundButton onclick={() => destroyAllModals()}>
73
+ <div class="close">
74
+ <RoundButton onclick={() => onclose()}>
95
75
  <IconClose />
96
76
  </RoundButton>
97
77
  </div>
@@ -101,7 +81,7 @@
101
81
 
102
82
  <!-- svelte-ignore a11y_click_events_have_key_events -->
103
83
  <!-- svelte-ignore a11y_no_static_element_interactions -->
104
- <div class="backdrop" onclick={() => destroyAllModals()}></div>
84
+ <div class="backdrop" onclick={() => onclose()}></div>
105
85
  </div>
106
86
 
107
87
  <style lang="scss">
@@ -213,20 +193,6 @@
213
193
  &:hover {
214
194
  filter: brightness(1.1);
215
195
  }
216
-
217
- &.flat {
218
- --playpilot-button-background: transparent;
219
- --playpilot-button-shadow: none;
220
- }
221
-
222
- &.back {
223
- right: auto;
224
- left: margin(1);
225
-
226
- &.flat {
227
- left: margin(0.5);
228
- }
229
- }
230
196
  }
231
197
 
232
198
  .prepend {
@@ -1,15 +1,17 @@
1
1
  <script lang="ts">
2
+ import Disclaimer from './Ads/Disclaimer.svelte'
2
3
  import { removeImageUrlPrefix } from '$lib/image'
3
4
  import { t } from '$lib/localization'
4
5
  import type { PlaylinkData } from '$lib/types/playlink'
5
6
 
6
7
  interface Props {
7
8
  playlink: PlaylinkData
9
+ disclaimer?: string
8
10
  hideCategory?: boolean
9
11
  onclick?: () => void
10
12
  }
11
13
 
12
- const { playlink, hideCategory = false, onclick = () => null }: Props = $props()
14
+ const { playlink, disclaimer = '', hideCategory = false, onclick = () => null }: Props = $props()
13
15
 
14
16
  const { name, url, logo_url, highlighted, cta_text, action_text, extra_info: { category } } = $derived(playlink)
15
17
 
@@ -38,6 +40,10 @@
38
40
  <div class="action">
39
41
  {action_text || t('Watch')}
40
42
  </div>
43
+
44
+ {#if disclaimer}
45
+ <Disclaimer {disclaimer} small />
46
+ {/if}
41
47
  </div>
42
48
  </a>
43
49
 
@@ -28,7 +28,9 @@
28
28
  // otherwise break the layout in ways that don't make sense to fix.
29
29
  const list = $derived(outerWidth < 500 || !!displayAd)
30
30
 
31
- const mergedPlaylink = $derived(mergePlaylinks(playlinks))
31
+ // Remove any playlinks without logos, these are likely sub providers.
32
+ const filteredPlaylinks = $derived(playlinks.filter(playlink => !!playlink.logo_url))
33
+ const mergedPlaylink = $derived(mergePlaylinks(filteredPlaylinks))
32
34
 
33
35
  function onclick(playlink: string): void {
34
36
  track(isModal ? TrackingEvent.TitleModalPlaylinkClick : TrackingEvent.TitlePopoverPlaylinkClick, title, { playlink })
@@ -50,7 +52,7 @@
50
52
 
51
53
  <!-- A fake highlighted playlink as part of the display ad, to be shown after the first playlink -->
52
54
  {#if displayAd && (index === 0)}
53
- <Playlink playlink={campaignToPlaylink(displayAd)} onclick={() => track(TrackingEvent.DisplayedAdPlaylickClick, title, { campaign_name: displayAd.campaign_name })} hideCategory />
55
+ <Playlink playlink={campaignToPlaylink(displayAd)} onclick={() => track(TrackingEvent.DisplayedAdPlaylickClick, title, { campaign_name: displayAd.campaign_name })} hideCategory disclaimer={displayAd.disclaimer || ''} />
54
56
  {/if}
55
57
  {/each}
56
58
 
@@ -3,12 +3,10 @@
3
3
  import Playlinks from './Playlinks.svelte'
4
4
  import Description from './Description.svelte'
5
5
  import IconIMDb from './Icons/IconIMDb.svelte'
6
- import Participants from './Participants.svelte'
7
6
  import { t } from '$lib/localization'
8
7
  import type { TitleData } from '$lib/types/title'
9
8
  import { heading } from '$lib/actions/heading'
10
9
  import { removeImageUrlPrefix } from '$lib/image'
11
- import { participants } from '$lib/fakeData'
12
10
 
13
11
  interface Props {
14
12
  title: TitleData
@@ -60,10 +58,6 @@
60
58
 
61
59
  {#if !small}
62
60
  <Description text={title.description} blurb={title.blurb} />
63
-
64
- {#if true || title.participants?.length}
65
- <Participants participants={participants} />
66
- {/if}
67
61
  {/if}
68
62
  </div>
69
63
  </div>
@@ -116,14 +110,14 @@
116
110
  }
117
111
 
118
112
  &.small {
119
- font-size: var(--playpilot-detail-font-size-small, 12px);
113
+ font-size: var(--playpilot-detail-font-size, 12px);
120
114
  line-height: 1.45;
121
115
  padding-bottom: margin(0.5);
122
116
  }
123
117
  }
124
118
 
125
119
  .header {
126
- padding: margin(3) 0 margin(1);
120
+ padding: margin(2) 0 margin(1);
127
121
  background: transparent;
128
122
 
129
123
  .small & {