@playpilot/tpi 8.10.2 → 8.10.4-beta.1

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 (37) hide show
  1. package/.env +1 -1
  2. package/dist/editorial.mount.js +9 -9
  3. package/dist/link-injections.js +2 -2
  4. package/dist/mount.js +6 -6
  5. package/package.json +1 -1
  6. package/src/lib/api/externalPages.ts +4 -0
  7. package/src/lib/enums/TrackingEvent.ts +4 -4
  8. package/src/lib/fakeData.ts +32 -44
  9. package/src/lib/injection.ts +9 -10
  10. package/src/lib/meta.ts +2 -1
  11. package/src/lib/modal.ts +1 -3
  12. package/src/lib/popover.ts +12 -13
  13. package/src/lib/types/injection.d.ts +0 -5
  14. package/src/routes/+layout.svelte +6 -1
  15. package/src/routes/+page.svelte +2 -0
  16. package/src/routes/components/Editorial/Editor.svelte +3 -2
  17. package/src/routes/components/Editorial/EditorItem.svelte +9 -23
  18. package/src/routes/components/Editorial/ManualInjection.svelte +0 -1
  19. package/src/routes/components/ListTitle.svelte +6 -27
  20. package/src/routes/components/Participant.svelte +6 -18
  21. package/src/routes/components/Playlinks/Playlinks.svelte +1 -2
  22. package/src/routes/components/Title.svelte +1 -1
  23. package/src/routes/components/{InjectionPopover.svelte → TitlePopover.svelte} +9 -26
  24. package/src/routes/elements/+page.svelte +3 -3
  25. package/src/tests/helpers.js +0 -1
  26. package/src/tests/lib/injection.test.js +3 -44
  27. package/src/tests/lib/meta.test.js +11 -2
  28. package/src/tests/lib/popover.test.js +7 -7
  29. package/src/tests/routes/components/Editorial/EditorItem.test.js +0 -10
  30. package/src/tests/routes/components/Editorial/ManualInjection.test.js +0 -4
  31. package/src/tests/routes/components/Editorial/PlaylinkTypeSelect.test.js +0 -2
  32. package/src/tests/routes/components/ListTitle.test.js +0 -7
  33. package/src/tests/routes/components/Participant.test.js +0 -7
  34. package/src/tests/routes/components/Playlinks/AfterArticlePlaylinks.test.js +0 -4
  35. package/src/tests/routes/components/Playlinks/Playlinks.test.js +1 -1
  36. package/src/tests/routes/components/TitlePopover.test.js +78 -0
  37. package/src/tests/routes/components/InjectionPopover.test.js +0 -117
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.10.2",
3
+ "version": "8.10.4-beta.1",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -26,6 +26,8 @@ export async function fetchLinkInjections(
26
26
  const apiUrl = `/external-pages/?api-token=${apiToken}&include_title_details=true${isEditorialMode ? '&editorial_mode_enabled=true' : ''}&language=${language}`
27
27
  let response: LinkInjectionResponse
28
28
 
29
+ console.log('page text in fetchLinkInjections', { pageText })
30
+
29
31
  // We use separate requests when running the AI or setting the editor session vs when only getting the results.
30
32
  // For regular requests we use a GET endpoint, but when saving data we POST to the same url.
31
33
  if (method === 'POST') {
@@ -70,6 +72,8 @@ export async function pollLinkInjections(
70
72
  // This is mostly handy during HMR, but also during navigation changes
71
73
  if (pollTimeout) clearTimeout(pollTimeout)
72
74
 
75
+ console.log('page text in pollLinkInjections', { pageText })
76
+
73
77
  const poll = async (resolve: Function, reject: Function): Promise<void> => {
74
78
  let response
75
79
  try {
@@ -16,10 +16,10 @@ export const TrackingEvent = {
16
16
  ParticipantModalClose: 'ali_participant_modal_close',
17
17
 
18
18
  // Popover
19
- InjectionPopoverView: 'ali_injection_popover_view',
20
- InjectionPopoverClose: 'ali_injection_popover_close',
21
- InjectionPopoverSaveClick: 'ali_injection_popover_save_click',
22
- InjectionPopoverPlaylinkClick: 'ali_injection_popover_playlink_click',
19
+ TitlePopoverView: 'ali_title_popover_view',
20
+ TitlePopoverClose: 'ali_title_popover_close',
21
+ TitlePopoverSaveClick: 'ali_title_popover_save_click',
22
+ TitlePopoverPlaylinkClick: 'ali_title_popover_playlink_click',
23
23
 
24
24
  // Rails
25
25
  SimilarTitleClick: 'ali_similar_title_click',
@@ -43,6 +43,38 @@ export const title: TitleData = {
43
43
  embeddable_url: null,
44
44
  }
45
45
 
46
+ export const linkInjections: LinkInjection[] = [{
47
+ sid: '1',
48
+ title: 'Quan',
49
+ sentence: 'In an interview with Epire Magazine, Quan reveals he quested starring in Love Hurts',
50
+ playpilot_url: 'https://playpilot.com/movie/example/',
51
+ key: 'some-key-1',
52
+ title_details: title,
53
+ }, {
54
+ sid: '2',
55
+ title: 'The Long Kiss Goodnight',
56
+ sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
57
+ playpilot_url: 'https://playpilot.com/movie/example-2/',
58
+ key: 'some-key-2',
59
+ after_article: false,
60
+ title_details: title,
61
+ }, {
62
+ sid: '3',
63
+ title: 'Nobody',
64
+ sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
65
+ playpilot_url: 'https://playpilot.com/movie/example-3/',
66
+ key: 'some-key-3',
67
+ after_article: true,
68
+ title_details: title,
69
+ manual: false,
70
+ }, {
71
+ sid: '4',
72
+ title: 'The Wheel of Time',
73
+ sentence: '(The more I think about the Bene Gesserit the more I see how much they influenced not just the Jedi in Star Wars but also the Aes Sedai in The Wheel of Time and even the sorceresses in The Witcher books, though Herbert\'s order is the most ominous and terrifying of them all)',
74
+ playpilot_url: 'https://playpilot.com/movie/example-4/',
75
+ key: 'some-key-4',
76
+ }]
77
+
46
78
  export const participants: ParticipantData[] = [
47
79
  {
48
80
  sid: 'pr5C5W',
@@ -112,50 +144,6 @@ export const participants: ParticipantData[] = [
112
144
  },
113
145
  ]
114
146
 
115
- export const linkInjections: LinkInjection[] = [{
116
- sid: '1',
117
- title: 'Quan',
118
- sentence: 'In an interview with Epire Magazine, Quan reveals he quested starring in Love Hurts',
119
- playpilot_url: 'https://playpilot.com/movie/example/',
120
- key: 'some-key-1',
121
- title_details: title,
122
- type: 'title',
123
- }, {
124
- sid: '2',
125
- title: 'The Long Kiss Goodnight',
126
- sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
127
- playpilot_url: 'https://playpilot.com/movie/example-2/',
128
- key: 'some-key-2',
129
- after_article: false,
130
- title_details: title,
131
- type: 'title',
132
- }, {
133
- sid: '3',
134
- title: 'Nobody',
135
- sentence: 'The movie is in a similar vein to successful films such as The Long Kiss Goodnight and Nobody',
136
- playpilot_url: 'https://playpilot.com/movie/example-3/',
137
- key: 'some-key-3',
138
- after_article: true,
139
- title_details: title,
140
- manual: false,
141
- type: 'title',
142
- }, {
143
- sid: '4',
144
- title: 'The Wheel of Time',
145
- sentence: '(The more I think about the Bene Gesserit the more I see how much they influenced not just the Jedi in Star Wars but also the Aes Sedai in The Wheel of Time and even the sorceresses in The Witcher books, though Herbert\'s order is the most ominous and terrifying of them all)',
146
- playpilot_url: 'https://playpilot.com/movie/example-4/',
147
- key: 'some-key-4',
148
- type: 'title',
149
- }, {
150
- sid: '5',
151
- title: 'Jack Black',
152
- sentence: 'Jason Momoa (”Aquaman”), Jack Black (”Nacho Libre”) och Jennifer Coolidge (”The White Lotus”) medverkar i den Jared Hess-regisserade (”Napolen Dynamite”) filmen.',
153
- playpilot_url: 'https://playpilot.com/name/pr875J-jack-black/',
154
- key: 'some-key-5',
155
- participant_details: participants[2],
156
- type: 'participant',
157
- }]
158
-
159
147
  export const campaign: Campaign = {
160
148
  campaign_format: 'card',
161
149
  campaign_type: 'image',
@@ -168,7 +168,7 @@ export function injectLinksInDocument(elements: HTMLElement[], injections: LinkI
168
168
  // The function itself will decide whether or not it should actually insert the component based on the config.
169
169
  if (document.querySelector(keySelector)) insertInTextDisclaimer(elements)
170
170
 
171
- return mergedInjections.filter(injection => hasValidTypeData(injection)).map((injection, index) => {
171
+ return mergedInjections.filter(i => i.title_details).map((injection, index) => {
172
172
  const hasManualEquivalent = !injection.manual && isAvailableAsManualInjection(injection, index, mergedInjections)
173
173
  const duplicate = injection.duplicate ?? hasManualEquivalent
174
174
 
@@ -376,11 +376,11 @@ export function separateLinkInjectionTypes(injections: LinkInjection[]): LinkInj
376
376
  }
377
377
 
378
378
  export function isValidInjection(injection: LinkInjection): boolean {
379
- return !injection.inactive && !injection.removed && !injection.duplicate && hasValidTypeData(injection) && isValidPlaylinkType(injection)
379
+ return !injection.inactive && !injection.removed && !injection.duplicate && !!injection.title_details && isValidPlaylinkType(injection)
380
380
  }
381
381
 
382
382
  /**
383
- * An injection can be of various playlink types, when all are false equivalent, the link is not valid.
383
+ * An injection can have be of various playlink types, when all are false equivalent, the link is not valid.
384
384
  * It should be treated similar to an inactive playlink in this case.
385
385
  */
386
386
  export function isValidPlaylinkType(injection: LinkInjection): boolean {
@@ -388,10 +388,16 @@ export function isValidPlaylinkType(injection: LinkInjection): boolean {
388
388
  return !!injection.after_article
389
389
  }
390
390
 
391
+ /**
392
+ * Filter links for in-text injections, removing after article, inactive, removed, duplicate, and items without title_details
393
+ */
391
394
  export function filterInvalidInTextInjections(injections: LinkInjection[]): LinkInjection[] {
392
395
  return filterRemovedAndInactiveInjections(injections).filter(i => i.in_text !== false && isValidInjection(i))
393
396
  }
394
397
 
398
+ /**
399
+ * Filter links for after article injections, removing in-text only, inactive, removed, duplicate, and items without title_details
400
+ */
395
401
  export function filterInvalidAfterArticleInjections(injections: LinkInjection[]): LinkInjection[] {
396
402
  return filterRemovedAndInactiveInjections(injections).filter(i => i.after_article === true && isValidInjection(i))
397
403
  }
@@ -436,13 +442,6 @@ export function isEquivalentInjection(injection1: LinkInjection, injection2: Lin
436
442
  return injection1.title === injection2.title && cleanPhrase(injection1.sentence) === cleanPhrase(injection2.sentence)
437
443
  }
438
444
 
439
- export function hasValidTypeData(injection: LinkInjection): boolean {
440
- if (injection.type === 'title' && !!injection.title_details) return true
441
- if (injection.type === 'participant' && !!injection.participant_details) return true
442
-
443
- return false
444
- }
445
-
446
445
  export function getPlayPilotWrapperElement(): Element {
447
446
  return document.querySelector('[data-playpilot-link-injections]') || document.body
448
447
  }
package/src/lib/meta.ts CHANGED
@@ -68,7 +68,8 @@ export function getDatetime(datetime: string): string | null {
68
68
  }
69
69
 
70
70
  export function getSchemaJson(): Record<string, any> {
71
- const schemaElement = document.querySelector('[type="application/ld+json"]')
71
+ const schemaElements = Array.from(document.querySelectorAll('[type="application/ld+json"]'))
72
+ const schemaElement = schemaElements.find(element => element.textContent.includes('dateModified') || element.textContent.includes('datePublished'))
72
73
 
73
74
  if (!schemaElement) return {}
74
75
 
package/src/lib/modal.ts CHANGED
@@ -133,9 +133,7 @@ export function openModalForInjectedLink(event: MouseEvent, injections: LinkInje
133
133
  event.preventDefault()
134
134
 
135
135
  playFallbackViewTransition(() => {
136
- const data = injection.title_details || injection.participant_details
137
-
138
136
  destroyLinkPopover(false)
139
- openModal({ event, injection, data, type: injection.type })
137
+ openModal({ event, injection, data: injection.title_details })
140
138
  }, !prefersReducedMotion.current && window.innerWidth >= mobileBreakpoint && !window.matchMedia('(pointer: coarse)').matches)
141
139
  }
@@ -1,30 +1,29 @@
1
1
  import { mount, unmount } from 'svelte'
2
+ import TitlePopover from '../routes/components/TitlePopover.svelte'
2
3
  import { getPlayPilotWrapperElement, keyDataAttribute, keySelector } from './injection'
3
4
  import type { LinkInjection } from './types/injection'
4
- import InjectionPopover from '../routes/components/InjectionPopover.svelte'
5
5
 
6
6
  export let currentlyHoveredInjection: EventTarget | null = null
7
7
  export let activePopoverInsertedComponent: object | null = null
8
8
 
9
+ /**
10
+ * When a link is hovered it is shown as a popover. The component is mounted when a mouse enters the link,
11
+ * and removed when clicked or on mouseleave.
12
+ */
9
13
  export function openPopoverForInjectedLink(event: MouseEvent, injection: LinkInjection): void {
14
+ // Skip touch devices
10
15
  if (window.matchMedia('(pointer: coarse)').matches) return
11
16
  if (activePopoverInsertedComponent) destroyLinkPopover()
12
17
 
13
- const currentTarget = event.currentTarget as Element
14
- currentlyHoveredInjection = currentTarget
18
+ const target = event.currentTarget as Element
19
+ currentlyHoveredInjection = target
15
20
 
16
21
  // Only show if the link is hovered for more than 100ms. This is to prevent the popover from showing
17
22
  // when a user just happens to mouseover as they are moving their mouse about.
18
23
  setTimeout(() => {
19
- if (currentlyHoveredInjection !== currentTarget) return
24
+ if (currentlyHoveredInjection !== target) return // User is no longer hovering this link
20
25
 
21
- const target = getPlayPilotWrapperElement()
22
-
23
- if (injection.type === 'title') {
24
- activePopoverInsertedComponent = mount(InjectionPopover, { target, props: { event, type: 'title', data: injection.title_details! } })
25
- } else if (injection.type === 'participant') {
26
- activePopoverInsertedComponent = mount(InjectionPopover, { target, props: { event, type: 'participant', data: injection.participant_details! } })
27
- }
26
+ activePopoverInsertedComponent = mount(TitlePopover, { target: getPlayPilotWrapperElement(), props: { event, title: injection.title_details! } })
28
27
  }, 100)
29
28
  }
30
29
 
@@ -45,7 +44,7 @@ export async function destroyLinkPopover(outro: boolean = true): Promise<void> {
45
44
  // In that case we remove the element straight from the dom.
46
45
  // Doing this will prevent the outro animation from playing, but this being a fallback, that's ok.
47
46
  // TODO: Find the actual cause of this bug.
48
- document.querySelectorAll<HTMLElement>('[data-playpilot-injection-popover]').forEach(element => element.remove())
47
+ document.querySelectorAll<HTMLElement>('[data-playpilot-title-popover]').forEach(element => element.remove())
49
48
  }
50
49
 
51
50
  export function destroyLinkPopoverOnMouseleave(event: MouseEvent): void {
@@ -54,7 +53,7 @@ export function destroyLinkPopoverOnMouseleave(event: MouseEvent): void {
54
53
  const target = event.target as Element
55
54
 
56
55
  // Mousemove is inside of popover or link that popover
57
- if (target.hasAttribute('data-playpilot-injection-popover') || target.closest('[data-playpilot-injection-popover]') ||
56
+ if (target.hasAttribute('data-playpilot-title-popover') || target.closest('[data-playpilot-title-popover]') ||
58
57
  target.hasAttribute(keyDataAttribute) || target.closest(keySelector)) return
59
58
 
60
59
  destroyLinkPopover()
@@ -1,8 +1,5 @@
1
- import type { ParticipantData } from './participant'
2
1
  import type { TitleData } from './title'
3
2
 
4
- export type LinkInjectionDataType = 'title' | 'participant'
5
-
6
3
  export type LinkInjection = {
7
4
  sid: string
8
5
  title: string
@@ -10,7 +7,6 @@ export type LinkInjection = {
10
7
  playpilot_url: string
11
8
  key: string
12
9
  title_details?: TitleData
13
- participant_details?: ParticipantData
14
10
  phrase_before?: string | null
15
11
  phrase_after?: string | null
16
12
  inactive?: boolean
@@ -23,7 +19,6 @@ export type LinkInjection = {
23
19
  removed?: boolean
24
20
  duplicate?: boolean
25
21
  matchingElement?: null | Element
26
- type: LinkInjectionDataType
27
22
  }
28
23
 
29
24
  export type LinkInjectionRanges = Record<string, { elementIndex: number, from: number, to: number }>
@@ -128,9 +128,14 @@
128
128
  line-height: 1.8;
129
129
 
130
130
  nav {
131
- display: flex;
131
+ display: grid;
132
+ grid-template-columns: 1fr 1fr;
132
133
  gap: margin(1);
133
134
 
135
+ @include desktop {
136
+ display: flex;
137
+ }
138
+
134
139
  a {
135
140
  padding: margin(0.25) margin(0.75);
136
141
  border: 1px solid currentColor;
@@ -37,6 +37,8 @@
37
37
 
38
38
  const pageText = $derived(getPageText(elements))
39
39
 
40
+ $inspect({ thing: 'pageText in page.svelte', pageText })
41
+
40
42
  const initializePromise = initialize()
41
43
 
42
44
  $effect(() => {
@@ -58,7 +58,8 @@
58
58
  const linkInjectionsString = $derived(JSON.stringify(linkInjections))
59
59
  const showControls = $derived(!aiRunning && allowEditing)
60
60
  const hasChanged = $derived(initialStateString && initialStateString !== linkInjectionsString)
61
- const filteredInjections = $derived(linkInjections.filter((i) => (i.title_details || i.participant_details) && !i.removed && !i.duplicate && (i.manual || (!i.manual && !i.failed))))
61
+ // Filter out injections without title_details, injections that are removed, duplicate, or are AI injections that failed to inject
62
+ const filteredInjections = $derived(linkInjections.filter((i) => i.title_details && !i.removed && !i.duplicate && (i.manual || (!i.manual && !i.failed))))
62
63
  const sortedInjections = $derived(sortInjections(filteredInjections))
63
64
  const initialAiRunning = $derived(!loading && untrack(() => aiStatus.aiRunning))
64
65
 
@@ -74,7 +75,7 @@
74
75
  function sortInjections(injections: LinkInjection[]): LinkInjection[] {
75
76
  return injections.sort((a, b) => {
76
77
  if (a.failed !== b.failed) return a.failed ? 1 : -1
77
- return (a.title_details?.title || a.participant_details?.name)!.localeCompare((b.title_details?.title || b.participant_details?.name)!)
78
+ return a.title_details!.title.localeCompare(b.title_details!.title)
78
79
  })
79
80
  }
80
81
 
@@ -11,6 +11,7 @@
11
11
  import { track } from '$lib/tracking'
12
12
  import { TrackingEvent } from '$lib/enums/TrackingEvent'
13
13
  import type { LinkInjection } from '$lib/types/injection'
14
+ import type { TitleData } from '$lib/types/title'
14
15
  import { cleanPhrase, truncateAroundPhrase } from '$lib/text'
15
16
  import { isValidPlaylinkType } from '$lib/injection'
16
17
  import { getLinkInjectionElements, getLinkInjectionsParentElement } from '$lib/injectionElements'
@@ -26,8 +27,9 @@
26
27
 
27
28
  const { linkInjection = $bindable(), onremove = () => null, onhighlight = () => null }: Props = $props()
28
29
 
29
- const { key, type, sentence, title_details, participant_details, failed, failed_message, inactive } = $derived(linkInjection || {})
30
+ const { key, sentence, title_details, failed, failed_message, inactive } = $derived(linkInjection || {})
30
31
 
32
+ const title: TitleData = $derived(title_details!)
31
33
  const truncatedSentence = $derived(truncateAroundPhrase(linkInjection.sentence, linkInjection.title, 60))
32
34
 
33
35
  let expanded = $state(false)
@@ -36,7 +38,7 @@
36
38
  let element: HTMLElement | null = $state(null)
37
39
 
38
40
  onMount(() => {
39
- if (failed) track(TrackingEvent.InjectionFailed, type === 'title' ? title_details : null, { phrase: linkInjection.title, sentence})
41
+ if (failed) track(TrackingEvent.InjectionFailed, title, { phrase: linkInjection.title, sentence})
40
42
  })
41
43
 
42
44
  /**
@@ -111,14 +113,10 @@
111
113
  bind:this={element}
112
114
  out:slide|global={{ duration: 200 }}>
113
115
  <div class="header">
114
- {#if type === 'title'}
115
- <img class="poster" src={removeImageUrlPrefix(title_details!.standing_poster)} alt="" width="32" height="48" onerror={({ target }) => (target as HTMLImageElement).src = imagePlaceholderDataUrl} />
116
- {:else}
117
- <div class="placeholder-image"></div>
118
- {/if}
116
+ <img class="poster" src={removeImageUrlPrefix(title.standing_poster)} alt="" width="32" height="48" onerror={({ target }) => (target as HTMLImageElement).src = imagePlaceholderDataUrl} />
119
117
 
120
118
  <div class="info">
121
- <div class="title">{title_details?.title || participant_details?.name}</div>
119
+ <div class="title">{title.title}</div>
122
120
 
123
121
  <div class="sentence">
124
122
  <!-- eslint-disable-next-line svelte/no-at-html-tags -->
@@ -145,13 +143,9 @@
145
143
  <Alert>{failed_message}</Alert>
146
144
  {:else}
147
145
  <div class="actions">
148
- {#if type === 'title'}
149
- <button class="expand" onclick={() => expanded = !expanded} aria-label="Expand" aria-expanded={expanded}>
150
- <IconChevron {expanded} />
151
- </button>
152
- {:else}
153
- <div></div>
154
- {/if}
146
+ <button class="expand" onclick={() => expanded = !expanded} aria-label="Expand" aria-expanded={expanded}>
147
+ <IconChevron {expanded} />
148
+ </button>
155
149
 
156
150
  {#if !isValidPlaylinkType(linkInjection)}
157
151
  <div class="warning" transition:fade={{ duration: 100 }} aria-label="Invalid playlink settings">
@@ -216,14 +210,6 @@
216
210
  }
217
211
  }
218
212
 
219
- .placeholder-image {
220
- flex: 0 0 margin(2);
221
- width: margin(2);
222
- height: margin(2);
223
- border-radius: 50%;
224
- background: theme(content);
225
- }
226
-
227
213
  .title {
228
214
  font-size: margin(0.875);
229
215
  word-break: break-word;
@@ -169,7 +169,6 @@
169
169
  key: generateInjectionKey(selectedTitle.sid),
170
170
  title_details: selectedTitle,
171
171
  manual: true,
172
- type: 'title',
173
172
  }
174
173
 
175
174
  onsave(linkInjection)
@@ -8,16 +8,15 @@
8
8
 
9
9
  interface Props {
10
10
  title: TitleData
11
- compact?: boolean
12
11
  onclick?: (event: MouseEvent) => void
13
12
  }
14
13
 
15
- const { title, compact = false, onclick = () => null }: Props = $props()
14
+ const { title, onclick = () => null }: Props = $props()
16
15
 
17
16
  const noAffiliate = !!window.PlayPilotLinkInjections?.no_affiliate
18
17
  </script>
19
18
 
20
- <button class="title" class:compact {onclick} data-testid="title">
19
+ <button class="title" {onclick} data-testid="title">
21
20
  <div class="poster">
22
21
  <TitlePoster {title} width={30} height={43} lazy />
23
22
  </div>
@@ -39,14 +38,12 @@
39
38
  {/if}
40
39
  </div>
41
40
 
42
- {#if !compact}
43
- <div class="description" class:large={noAffiliate}>
44
- {title.description}
45
- </div>
46
- {/if}
41
+ <div class="description" class:large={noAffiliate}>
42
+ {title.description}
43
+ </div>
47
44
 
48
45
  {#if !noAffiliate}
49
- <PlaylinksCompact playlinks={title.providers} size={compact ? 24 : 30} />
46
+ <PlaylinksCompact playlinks={title.providers} />
50
47
  {/if}
51
48
  </div>
52
49
 
@@ -87,10 +84,6 @@
87
84
  border-radius: theme(detail-image-border-radius, border-radius);
88
85
  background: theme(detail-image-background, content);
89
86
  overflow: hidden;
90
-
91
- .compact & {
92
- width: margin(3.5);
93
- }
94
87
  }
95
88
 
96
89
  .content {
@@ -104,17 +97,11 @@
104
97
  @include desktop() {
105
98
  padding-right: margin(1);
106
99
  }
107
-
108
- .compact & {
109
- padding-left: margin(0.75);
110
- padding-right: 0;
111
- }
112
100
  }
113
101
 
114
102
  .heading {
115
103
  color: theme(list-item-title-text-color, text-color);
116
104
  font-weight: theme(list-item-title-font-weight, font-bold);
117
- line-height: 1.2;
118
105
  }
119
106
 
120
107
  .meta {
@@ -129,10 +116,6 @@
129
116
  > div {
130
117
  text-transform: capitalize;
131
118
  }
132
-
133
- .compact & {
134
- margin: margin(0.125) 0 margin(0.25) 0;
135
- }
136
119
  }
137
120
 
138
121
  .imdb {
@@ -169,9 +152,5 @@
169
152
  &:active {
170
153
  color: theme(list-item-action-hover-color, text-color);
171
154
  }
172
-
173
- .compact & {
174
- display: none;
175
- }
176
155
  }
177
156
  </style>
@@ -13,10 +13,9 @@
13
13
 
14
14
  interface Props {
15
15
  participant: ParticipantData
16
- small?: boolean
17
16
  }
18
17
 
19
- const { participant, small = false }: Props = $props()
18
+ const { participant }: Props = $props()
20
19
 
21
20
  const { name, birth_date, death_date } = $derived(participant)
22
21
 
@@ -53,8 +52,8 @@
53
52
  }
54
53
  </script>
55
54
 
56
- <div class="header" class:small>
57
- <div class="heading" use:heading={2} id="heading">{name}</div>
55
+ <div class="header">
56
+ <div class="heading" use:heading={2} id="name">{name}</div>
58
57
 
59
58
  {#if birth_date}
60
59
  <p class="dates">
@@ -64,13 +63,11 @@
64
63
  </div>
65
64
 
66
65
  <div class="content">
67
- {#if !small}
68
- <div class="heading subheading" use:heading={3} id="credits">{t('Credits')}</div>
69
- {/if}
66
+ <div class="heading small" use:heading={3} id="credits">{t('Credits')}</div>
70
67
 
71
68
  <div class="list">
72
69
  {#each titles as title}
73
- <ListTitle {title} compact={small} onclick={(event) => openModal({ event, data: title })} />
70
+ <ListTitle {title} onclick={(event) => openModal({ event, data: title })} />
74
71
  {/each}
75
72
 
76
73
  {#if loading}
@@ -91,10 +88,6 @@
91
88
  font-size: theme(detail-font-size, font-size-base);
92
89
  line-height: theme(participant-description-line-height, normal);
93
90
  color: theme(detail-text-color, text-color);
94
-
95
- &.small {
96
- padding: margin(1);
97
- }
98
91
  }
99
92
 
100
93
  .heading {
@@ -105,7 +98,7 @@
105
98
  line-height: normal;
106
99
  font-style: theme(detail-title-font-style, normal);
107
100
 
108
- &.subheading {
101
+ &.small {
109
102
  margin: 0 0 margin(0.5);
110
103
  font-size: theme(detail-title-small-font-size, margin(1.25));
111
104
  }
@@ -123,11 +116,6 @@
123
116
  font-size: theme(detail-font-size, font-size-base);
124
117
  line-height: normal;
125
118
  font-style: normal;
126
-
127
- ::view-transition-old(content),
128
- ::view-transition-new(content) {
129
- height: 100%;
130
- }
131
119
  }
132
120
 
133
121
  .list {
@@ -22,7 +22,6 @@
22
22
  const { playlinks, title }: Props = $props()
23
23
 
24
24
  const isModal = getContext('scope') === 'modal'
25
- const type = getContext('type')
26
25
  const displayAd = getFirstAdOfType('card')
27
26
  const categorize = !!window.PlayPilotLinkInjections?.config?.categorize_playlinks
28
27
 
@@ -38,7 +37,7 @@
38
37
  const list = $derived(outerWidth < 500 || !!displayAd || mergedPlaylinks.length === 1)
39
38
 
40
39
  function onclick(playlink: string): void {
41
- track(isModal ? TrackingEvent.TitleModalPlaylinkClick : TrackingEvent.InjectionPopoverPlaylinkClick, title, { playlink, type })
40
+ track(isModal ? TrackingEvent.TitleModalPlaylinkClick : TrackingEvent.TitlePopoverPlaylinkClick, title, { playlink })
42
41
  }
43
42
 
44
43
  function categorizePlaylinks(playlinks: PlaylinkData[]): CategorizedPlaylinks {
@@ -55,7 +55,7 @@
55
55
  <TitlePoster {title} onload={() => posterLoaded = true} lazy={false} />
56
56
  </div>
57
57
 
58
- <div class="heading" use:heading={2} class:truncate={small} id="heading">{title.title}</div>
58
+ <div class="heading" use:heading={2} class:truncate={small} id="title">{title.title}</div>
59
59
 
60
60
  <div class="info">
61
61
  <div class="imdb">