@playpilot/tpi 8.29.0-beta.4 → 8.29.0-beta.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playpilot/tpi",
3
- "version": "8.29.0-beta.4",
3
+ "version": "8.29.0-beta.6",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -1,3 +1,4 @@
1
+ import { participants } from '$lib/fakeData'
1
2
  import { getLanguage } from '$lib/language'
2
3
  import { getApiToken } from '$lib/token'
3
4
  import type { ParticipantData } from '$lib/types/participant'
@@ -25,3 +26,17 @@ export async function fetchParticipantsForTitle(title: TitleData): Promise<Parti
25
26
 
26
27
  return response.results
27
28
  }
29
+
30
+ export async function fetchParticipantBySid(sid: string): Promise<ParticipantData> {
31
+ await new Promise(res => setTimeout(res, 200))
32
+
33
+ return participants[0]
34
+
35
+ const data = await api<{ results: ParticipantData[] }>(`/participants/browse?api-token=${getApiToken()}&sids=${sid}`)
36
+
37
+ const participant = data.results[0]
38
+
39
+ if (!participant) throw new Error('No participant was returned for sid: ' + sid)
40
+
41
+ return participant
42
+ }
@@ -5,9 +5,9 @@ import { destroyAllModals, openModalForInjectedLink } from './modal'
5
5
  import { clearCurrentlyHoveredInjection, destroyLinkPopover, destroyLinkPopoverOnMouseleave, isPopoverActive, openPopoverForInjectedLink } from './popover'
6
6
  import { clearAfterArticlePlaylinks, insertAfterArticlePlaylinks } from './afterArticle'
7
7
  import { clearInTextDisclaimer, insertInTextDisclaimer } from './disclaimer'
8
- import { exploreTitleUrl, titleUrl } from './routes'
8
+ import { exploreModalUrl, participantUrl, titleUrl } from './routes'
9
9
  import { clearInTextWidgets, insertInTextWidgets } from './inTextWidgets'
10
- import { decodeHtmlEntities, encodeHtmlEntities } from './html'
10
+ import { encodeHtmlEntities } from './html'
11
11
 
12
12
  export const keyDataAttribute = 'data-playpilot-injection-key'
13
13
  export const keySelector = `[${keyDataAttribute}]`
@@ -32,9 +32,7 @@ export function injectLinksInDocument(elements: HTMLElement[], injections: LinkI
32
32
 
33
33
  const failedMessages: Record<string, string> = {}
34
34
 
35
- // Start at -1 so that we can add +1 right at the top of the loop, making it start at 0.
36
- // This index is used in Option 3 below.
37
- let injectionIndex = -1
35
+ let injectionIndex = -1 // This index is used in Option 3 below.
38
36
  for (const injection of sortInjections(foundInjections)) {
39
37
  injectionIndex++
40
38
 
@@ -218,10 +216,8 @@ function createLinkInjectionElement(injection: LinkInjection): { injectionElemen
218
216
 
219
217
  const openInExplore = !!window.PlayPilotLinkInjections?.config?.open_tpi_links_in_explore
220
218
 
221
- const href =
222
- injection.type === 'title' ?
223
- openInExplore ? exploreTitleUrl(injection.title_details!) : titleUrl(injection.title_details!) :
224
- '' // FIXME: We don't have participant streaming guide pages yet
219
+ const sid = injection.title_details?.sid || injection.participant_details?.sid
220
+ const href = openInExplore ? exploreModalUrl(sid!) : (injection.type === 'title' ? titleUrl(injection.title_details!) : participantUrl(injection.participant_details!))
225
221
 
226
222
  const linkElement = document.createElement('a')
227
223
  linkElement.innerText = injection.title
package/src/lib/modal.ts CHANGED
@@ -13,10 +13,12 @@ import { prefersReducedMotion } from 'svelte/motion'
13
13
  import TitlesRailModal from '../routes/components/Modals/TitlesRailModal.svelte'
14
14
  import TitlesReelModal from '../routes/components/Modals/TitlesReelModal.svelte'
15
15
 
16
+ export type ModalType = 'title' | 'participant' | 'titles-rail' | 'titles-reel'
17
+
16
18
  type Modal = {
17
19
  injection?: LinkInjection | null
18
20
  component?: object
19
- type: 'title' | 'participant' | 'titles-rail' | 'titles-reel'
21
+ type: ModalType
20
22
  data: TitleData | TitleData[] | ParticipantData | null
21
23
  scrollPosition?: number
22
24
  }
@@ -65,6 +67,8 @@ function addModalToList({ type = 'title', injection = null, data, scrollPosition
65
67
  export function closeCurrentModal(outro: boolean = true): void {
66
68
  if (!modals.length) return
67
69
 
70
+ console.trace('closeCurrentModal')
71
+
68
72
  saveCurrentModalScrollPosition()
69
73
 
70
74
  unmount(modals[modals.length - 1].component!, { outro })
package/src/lib/routes.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import { playPilotBaseUrl } from './constants'
2
+ import type { ParticipantData } from './types/participant'
2
3
  import type { TitleData } from './types/title'
3
4
 
4
5
  export function titleUrl(title: TitleData): string {
5
6
  return `${playPilotBaseUrl}/${title.type}/${title.slug}/`
6
7
  }
7
8
 
8
- export function exploreTitleUrl(title: TitleData): string {
9
- return window.PlayPilotLinkInjections?.config?.explore_navigation_path + `?route=modal&sid=${title.sid}`
9
+ export function participantUrl(participant: ParticipantData): string {
10
+ return `${playPilotBaseUrl}/name/${participant.sid}/`
11
+ }
12
+
13
+ export function exploreModalUrl(sid: string): string {
14
+ return window.PlayPilotLinkInjections?.config?.explore_navigation_path + `?route=modal&sid=${sid}`
10
15
  }
@@ -1,98 +1,106 @@
1
- <script lang="ts">
2
- import { fetchSimilarTitles, fetchTitleBySid } from '$lib/api/titles'
3
- import { mobileBreakpoint } from '$lib/constants'
4
- import { SplitTest } from '$lib/enums/SplitTest'
5
- import { t } from '$lib/localization'
6
- import { openModal } from '$lib/modal'
7
- import { getSplitTestVariantName, trackSplitTestView } from '$lib/splitTest'
8
- import type { TitleData } from '$lib/types/title'
9
- import Modal from '../../Modals/Modal.svelte'
10
-
11
- interface Props {
12
- navigate?: (key: string, pushState?: boolean) => void
13
- }
14
-
15
- const { navigate = () => null }: Props = $props()
16
-
17
- async function openModalViaRoute(): Promise<void> {
18
- const currentUrl = new URL(document.location.toString())
19
- const sid = currentUrl.searchParams.get('sid')
20
-
21
- if (!sid) return
22
-
23
- const isMobile = window.innerWidth < mobileBreakpoint
24
- const isInReelSplitTest = isMobile && getSplitTestVariantName(SplitTest.Reels) === 'Reel'
25
- const type = isMobile && isInReelSplitTest ? 'titles-reel' : 'titles-rail'
26
-
27
- if (isMobile) trackSplitTestView(SplitTest.Reels)
28
-
29
- const [title, railTitles] = (await Promise.allSettled([
30
- fetchTitleBySid(sid),
31
- fetchSimilarTitles({ sid } as unknown as TitleData)])
32
- ).map(promise => (promise.status === 'fulfilled' ? promise.value : null))
33
-
34
- openModal({
35
- type,
36
- data: [(title as TitleData), ...(railTitles as TitleData[])],
37
- props: {
38
- onclose: () => navigate('home'),
39
- pushState: false,
40
- },
41
- })
42
- }
43
- </script>
44
-
45
- {#await openModalViaRoute()}
46
- <Modal blur pushState={false}>
47
- {#snippet dialog()}
48
- <div class="loading">
49
- <div class="bar"></div>
50
- <div class="bar"></div>
51
- <div class="bar"></div>
52
- </div>
53
- {/snippet}
54
- </Modal>
55
- {:catch}
56
- <Modal blur onclose={() => navigate('home')} pushState={false}>
57
- <div class="error">
58
- {t('An Error Occurred')}
59
- </div>
60
- </Modal>
61
- {/await}
62
-
63
- <style lang="scss">
64
- .loading {
65
- display: flex;
66
- align-items: center;
67
- justify-content: center;
68
- height: 100%;
69
- gap: margin(0.5);
70
- }
71
-
72
- @keyframes animate-bar {
73
- to {
74
- height: margin(3);
75
- opacity: 0.5;
76
- }
77
- }
78
-
79
- .bar {
80
- height: margin(4);
81
- width: margin(1);
82
- border-radius: margin(0.25);
83
- background: white;
84
- animation: animate-bar 750ms infinite;
85
-
86
- @for $i from 0 through 2 {
87
- &:nth-child(#{$i}) {
88
- animation-delay: $i * 250ms;
89
- }
90
- }
91
- }
92
-
93
- .error {
94
- padding: margin(2);
95
- font-size: 1.25em;
96
- color: theme(text-color);
97
- }
98
- </style>
1
+ <script lang="ts">
2
+ import { fetchParticipantBySid } from '$lib/api/participants'
3
+ import { fetchSimilarTitles, fetchTitleBySid } from '$lib/api/titles'
4
+ import { mobileBreakpoint } from '$lib/constants'
5
+ import { SplitTest } from '$lib/enums/SplitTest'
6
+ import { t } from '$lib/localization'
7
+ import { openModal, type ModalType } from '$lib/modal'
8
+ import { getSplitTestVariantName, trackSplitTestView } from '$lib/splitTest'
9
+ import type { TitleData } from '$lib/types/title'
10
+ import Modal from '../../Modals/Modal.svelte'
11
+
12
+ interface Props {
13
+ navigate?: (key: string, pushState?: boolean) => void
14
+ }
15
+
16
+ const { navigate = () => null }: Props = $props()
17
+
18
+ async function openModalViaRoute(): Promise<void> {
19
+ const currentUrl = new URL(document.location.toString())
20
+ const sid = currentUrl.searchParams.get('sid')
21
+
22
+ if (!sid) return
23
+
24
+ let type: ModalType = sid.startsWith('pr') ? 'participant' : 'title' // Sids with with `pr` for participants, `ti` for titles
25
+ let data: any = null
26
+
27
+ if (type === 'title') {
28
+ const isMobile = window.innerWidth < mobileBreakpoint
29
+ const isInReelSplitTest = isMobile && getSplitTestVariantName(SplitTest.Reels) === 'Reel'
30
+
31
+ if (isMobile) trackSplitTestView(SplitTest.Reels)
32
+
33
+ type = isMobile && isInReelSplitTest ? 'titles-reel' : 'titles-rail'
34
+
35
+ const [title, railTitles] = (await Promise.allSettled([fetchTitleBySid(sid), fetchSimilarTitles({ sid } as unknown as TitleData)])).map((promise) => promise.status === 'fulfilled' ? promise.value : null)
36
+
37
+ data = [title as TitleData, ...(railTitles as TitleData[])]
38
+ } else if (type === 'participant') {
39
+ data = fetchParticipantBySid(sid)
40
+ }
41
+
42
+ openModal({
43
+ type,
44
+ data,
45
+ props: {
46
+ onclose: () => navigate('home'),
47
+ pushState: false,
48
+ },
49
+ })
50
+ }
51
+ </script>
52
+
53
+ {#await openModalViaRoute()}
54
+ <Modal blur pushState={false}>
55
+ {#snippet dialog()}
56
+ <div class="loading">
57
+ <div class="bar"></div>
58
+ <div class="bar"></div>
59
+ <div class="bar"></div>
60
+ </div>
61
+ {/snippet}
62
+ </Modal>
63
+ {:catch}
64
+ <Modal blur onclose={() => navigate('home')} pushState={false}>
65
+ <div class="error">
66
+ {t('An Error Occurred')}
67
+ </div>
68
+ </Modal>
69
+ {/await}
70
+
71
+ <style lang="scss">
72
+ .loading {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ height: 100%;
77
+ gap: margin(0.5);
78
+ }
79
+
80
+ @keyframes animate-bar {
81
+ to {
82
+ height: margin(3);
83
+ opacity: 0.5;
84
+ }
85
+ }
86
+
87
+ .bar {
88
+ height: margin(4);
89
+ width: margin(1);
90
+ border-radius: margin(0.25);
91
+ background: white;
92
+ animation: animate-bar 750ms infinite;
93
+
94
+ @for $i from 0 through 2 {
95
+ &:nth-child(#{$i}) {
96
+ animation-delay: $i * 250ms;
97
+ }
98
+ }
99
+ }
100
+
101
+ .error {
102
+ padding: margin(2);
103
+ font-size: 1.25em;
104
+ color: theme(text-color);
105
+ }
106
+ </style>
@@ -12,7 +12,7 @@
12
12
  initialScrollPosition?: number
13
13
  }
14
14
 
15
- const { participant, initialScrollPosition = 0 }: Props = $props()
15
+ const { participant, initialScrollPosition = 0, ...restProps }: Props = $props()
16
16
 
17
17
  let windowWidth = $state(0)
18
18
 
@@ -27,6 +27,6 @@
27
27
 
28
28
  <svelte:window bind:innerWidth={windowWidth} />
29
29
 
30
- <Modal {initialScrollPosition} closeButtonStyle="flat" tall>
30
+ <Modal {initialScrollPosition} {...restProps} closeButtonStyle="flat" tall>
31
31
  <Participant {participant} />
32
32
  </Modal>
@@ -5,7 +5,7 @@
5
5
  import Rail from './Rail.svelte'
6
6
  import type { TitleData } from '$lib/types/title'
7
7
  import { openModal } from '$lib/modal'
8
- import { exploreTitleUrl } from '$lib/routes'
8
+ import { exploreModalUrl } from '$lib/routes'
9
9
  import { generateRandomHash } from '$lib/hash'
10
10
  import { getFirstTitleWithAvailableTrailer } from '$lib/trailer'
11
11
  import { useExploreRouter } from '$lib/explore'
@@ -88,7 +88,7 @@
88
88
  onclick(title)
89
89
 
90
90
  if (navigateToExplore) {
91
- window.location.href = exploreTitleUrl(title)
91
+ window.location.href = exploreModalUrl(title.sid)
92
92
  return
93
93
  }
94
94
 
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { exploreTitleUrl, titleUrl } from '$lib/routes'
2
+ import { exploreModalUrl, participantUrl, titleUrl } from '$lib/routes'
3
3
  import { playPilotBaseUrl } from '$lib/constants'
4
- import { title } from '$lib/fakeData'
4
+ import { participants, title } from '$lib/fakeData'
5
5
 
6
6
  describe('$lib/routes', () => {
7
7
  describe('titleUrl', () => {
@@ -14,14 +14,19 @@ describe('$lib/routes', () => {
14
14
  })
15
15
  })
16
16
 
17
- describe('exploreTitleUrl', () => {
17
+ describe('participantUrl', () => {
18
+ it('Should return url for given title', () => {
19
+ expect(participantUrl(participants[0])).toBe(`${playPilotBaseUrl}/name/${participants[0].sid}/`)
20
+ })
21
+ })
22
+
23
+ describe('exploreModalUrl', () => {
18
24
  it('Should return url for given title', () => {
19
25
  window.PlayPilotLinkInjections.config = {
20
- open_tpi_links_in_explore: true,
21
26
  explore_navigation_path: 'https://some-path.com/explore',
22
27
  }
23
28
 
24
- expect(exploreTitleUrl(title)).toBe(`https://some-path.com/explore?route=modal&sid=${title.sid}`)
29
+ expect(exploreModalUrl(title.sid)).toBe(`https://some-path.com/explore?route=modal&sid=${title.sid}`)
25
30
  })
26
31
  })
27
32
  })