@playpilot/tpi 5.12.0-beta.similar.1 → 5.12.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 (44) hide show
  1. package/dist/link-injections.js +10 -11
  2. package/events.md +1 -0
  3. package/package.json +1 -2
  4. package/src/lib/enums/SplitTest.ts +1 -2
  5. package/src/lib/enums/TrackingEvent.ts +2 -1
  6. package/src/lib/fakeData.ts +0 -70
  7. package/src/lib/linkInjection.ts +55 -12
  8. package/src/lib/playlink.ts +1 -4
  9. package/src/lib/splitTest.ts +9 -2
  10. package/src/lib/types/title.d.ts +0 -2
  11. package/src/routes/+page.svelte +0 -1
  12. package/src/routes/components/Icons/IconClose.svelte +1 -1
  13. package/src/routes/components/Icons/IconScrollIndicator.svelte +3 -0
  14. package/src/routes/components/Modal.svelte +7 -41
  15. package/src/routes/components/Playlinks.svelte +3 -6
  16. package/src/routes/components/Popover.svelte +111 -12
  17. package/src/routes/components/Title.svelte +18 -33
  18. package/src/routes/components/TitleModal.svelte +3 -2
  19. package/src/routes/components/TitlePopover.svelte +2 -5
  20. package/src/tests/lib/linkInjection.test.js +35 -9
  21. package/src/tests/lib/playlink.test.js +10 -25
  22. package/src/tests/lib/splitTest.test.js +31 -3
  23. package/src/tests/routes/components/Modal.test.js +19 -51
  24. package/src/tests/routes/components/Title.test.js +0 -8
  25. package/src/tests/setup.js +10 -0
  26. package/src/lib/modal.ts +0 -81
  27. package/src/lib/types/participant.d.ts +0 -14
  28. package/src/routes/components/Icons/IconArrow.svelte +0 -17
  29. package/src/routes/components/ListTitle.svelte +0 -172
  30. package/src/routes/components/Participant.svelte +0 -88
  31. package/src/routes/components/ParticipantModal.svelte +0 -30
  32. package/src/routes/components/PlaylinkIcon.svelte +0 -41
  33. package/src/routes/components/Rails/ParticipantsRail.svelte +0 -56
  34. package/src/routes/components/Rails/Rail.svelte +0 -91
  35. package/src/routes/components/Rails/SimilarRail.svelte +0 -16
  36. package/src/routes/components/Rails/TitlesRail.svelte +0 -95
  37. package/src/routes/components/Tabs.svelte +0 -47
  38. package/src/routes/components/TitlePoster.svelte +0 -30
  39. package/src/tests/lib/modal.test.js +0 -148
  40. package/src/tests/routes/components/ListTitle.test.js +0 -82
  41. package/src/tests/routes/components/PlaylinkIcon.test.js +0 -27
  42. package/src/tests/routes/components/Rails/ParticipantsRail.test.js +0 -41
  43. package/src/tests/routes/components/Rails/TitleRail.test.js +0 -38
  44. package/src/tests/routes/components/TitlePoster.test.js +0 -20
@@ -1,63 +1,57 @@
1
1
  import { render, fireEvent } from '@testing-library/svelte'
2
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { describe, expect, it, vi } from 'vitest'
3
3
 
4
4
  import Modal from '../../../routes/components/Modal.svelte'
5
5
  import { createRawSnippet } from 'svelte'
6
- import { destroyAllModals, getPreviousModal, goBackToPreviousModal } from '$lib/modal'
7
-
8
- vi.mock('$lib/modal', () => ({
9
- destroyAllModals: vi.fn(),
10
- getPreviousModal: vi.fn(),
11
- goBackToPreviousModal: vi.fn(),
12
- }))
13
6
 
14
7
  describe('Modal.svelte', () => {
15
- beforeEach(() => {
16
- vi.resetAllMocks()
17
- })
18
-
19
8
  const children = createRawSnippet(() => ({ render: () => '<div></div>' }))
20
9
 
21
- it('Should fire given destroyAllModals function when backdrop is clicked', async () => {
22
- const { container } = render(Modal, { children })
10
+ it('Should fire given onclose function when backdrop is clicked', async () => {
11
+ const onclose = vi.fn()
12
+ const { container } = render(Modal, { children, onclose })
23
13
 
24
14
  await fireEvent.click(/** @type {Node} */ (container.querySelector('.backdrop')))
25
15
 
26
- expect(destroyAllModals).toHaveBeenCalled()
16
+ expect(onclose).toHaveBeenCalled()
27
17
  })
28
18
 
29
- it('Should fire destroyAllModals function when close button is clicked', async () => {
30
- const { container } = render(Modal, { children })
19
+ it('Should fire given onclose function when close button is clicked', async () => {
20
+ const onclose = vi.fn()
21
+ const { container } = render(Modal, { children, onclose })
31
22
 
32
23
  await fireEvent.click(/** @type {Node} */ (container.querySelector('button')))
33
24
 
34
- expect(destroyAllModals).toHaveBeenCalled()
25
+ expect(onclose).toHaveBeenCalled()
35
26
  })
36
27
 
37
28
  it('Should not fire given onclose function when dialog is clicked', async () => {
38
- const { container } = render(Modal, { children })
29
+ const onclose = vi.fn()
30
+ const { container } = render(Modal, { children, onclose })
39
31
 
40
32
  await fireEvent.click(/** @type {Node} */ (container.querySelector('.dialog')))
41
33
 
42
- expect(destroyAllModals).not.toHaveBeenCalled()
34
+ expect(onclose).not.toHaveBeenCalled()
43
35
  })
44
36
 
45
- it('Should fire given destroyAllModals function when escape key is pressed', async () => {
46
- render(Modal, { children })
37
+ it('Should fire given onclose function when escape key is pressed', async () => {
38
+ const onclose = vi.fn()
39
+ render(Modal, { children, onclose })
47
40
 
48
41
  fireEvent.keyDown(window, { key: 'Escape' })
49
42
 
50
- expect(destroyAllModals).toHaveBeenCalled()
43
+ expect(onclose).toHaveBeenCalled()
51
44
  })
52
45
 
53
46
  it('Should not fire given onclose function when key other than escape key is pressed', async () => {
54
- render(Modal, { children })
47
+ const onclose = vi.fn()
48
+ render(Modal, { children, onclose })
55
49
 
56
50
  fireEvent.keyDown(window, { key: 'a' })
57
51
  fireEvent.keyDown(window, { key: 'Enter' })
58
52
  fireEvent.keyDown(window, { key: 'Space' })
59
53
 
60
- expect(destroyAllModals).not.toHaveBeenCalled()
54
+ expect(onclose).not.toHaveBeenCalled()
61
55
  })
62
56
 
63
57
  it('Should fire given onscroll function when dialog is scrolled', async () => {
@@ -102,30 +96,4 @@ describe('Modal.svelte', () => {
102
96
 
103
97
  expect(getByRole('dialog').classList).toContain('tall')
104
98
  })
105
-
106
- it('Should not show back button by default', () => {
107
- const { queryByLabelText } = render(Modal, { children })
108
-
109
- expect(queryByLabelText('Back')).not.toBeTruthy()
110
- })
111
-
112
- it('Should show back button if previous modal was opened', () => {
113
- // @ts-ignore
114
- vi.mocked(getPreviousModal).mockReturnValueOnce(true)
115
-
116
- const { getByLabelText } = render(Modal, { children })
117
-
118
- expect(getByLabelText('Back')).toBeTruthy()
119
- })
120
-
121
- it('Should fire goBackToPreviousModal when back button is clicked', async () => {
122
- // @ts-ignore
123
- vi.mocked(getPreviousModal).mockReturnValueOnce(true)
124
-
125
- const { getByLabelText } = render(Modal, { children })
126
-
127
- await fireEvent.click(getByLabelText('Back'))
128
-
129
- expect(goBackToPreviousModal).toHaveBeenCalled()
130
- })
131
99
  })
@@ -68,12 +68,4 @@ describe('Title.svelte', () => {
68
68
 
69
69
  expect(queryByText('Some description')).not.toBeTruthy()
70
70
  })
71
-
72
- it('Should render as compacter version when compact prop is true', () => {
73
- const { queryByAltText, container } = render(Title, { title: { ...title, description: 'Some description' }, compact: true })
74
-
75
- expect(queryByAltText(`Movie poster for '${title.title}'`)).not.toBeTruthy()
76
- expect(container.querySelector('.compact')).toBeTruthy()
77
- expect(container.querySelector('.faded')).toBeTruthy()
78
- })
79
71
  })
@@ -56,9 +56,19 @@ const mockSessionStorage = () => {
56
56
  }
57
57
  }
58
58
 
59
+ const mockIntersectionObserver = () => {
60
+ // @ts-ignore
61
+ global.IntersectionObserver = vi.fn(() => ({
62
+ disconnect: vi.fn(),
63
+ observe: vi.fn(),
64
+ unobserve: vi.fn(),
65
+ }))
66
+ }
67
+
59
68
  beforeAll(() => {
60
69
  mockLocalStorage()
61
70
  mockSessionStorage()
71
+ mockIntersectionObserver()
62
72
  })
63
73
 
64
74
  beforeEach(() => {
package/src/lib/modal.ts DELETED
@@ -1,81 +0,0 @@
1
- import { mount, unmount } from "svelte"
2
- import { isHoldingSpecialKey } from "./event"
3
- import TitleModal from "../routes/components/TitleModal.svelte"
4
- import type { LinkInjection } from "./types/injection"
5
- import { getPlayPilotWrapperElement } from "./linkInjection"
6
- import ParticipantModal from "../routes/components/ParticipantModal.svelte"
7
- import type { TitleData } from "./types/title"
8
- import type { ParticipantData } from "./types/participant"
9
-
10
- type ModalType = 'title' | 'participant'
11
-
12
- type Modal = {
13
- injection?: LinkInjection | null
14
- component: object
15
- type: ModalType
16
- data: TitleData | ParticipantData | null
17
- }
18
-
19
- const modals: Modal[] = []
20
-
21
- /**
22
- * Open modal for the corresponding injection by mounting the component and saving it to a variable.
23
- * Ignore clicks that used modifier keys or that were not left click.
24
- */
25
- export function openModal(
26
- { type = 'title', event = null, injection = null, data = null }:
27
- { type?: ModalType, event?: MouseEvent | null, injection?: LinkInjection | null, data?: TitleData | ParticipantData | null, push?: boolean } = {}): void {
28
- if (event && isHoldingSpecialKey(event)) return
29
-
30
- event?.preventDefault()
31
-
32
- if (modals?.length) closeCurrentModal()
33
-
34
- const target = getPlayPilotWrapperElement()
35
- const component = type === 'title' ?
36
- mount(TitleModal, { target, props: { title: data as TitleData } }) :
37
- mount(ParticipantModal, { target, props: { participant: data as ParticipantData } })
38
-
39
- modals.push({ type, injection, data, component })
40
- }
41
-
42
- /** Unmount the last modal is the list of modals but keep it in the list of active modals */
43
- export function closeCurrentModal(outro: boolean = true): void {
44
- if (!modals.length) return
45
-
46
- unmount(modals[modals.length - 1].component, { outro })
47
- }
48
-
49
- /** Unmount the last modal is the list of modals and remove it from the list */
50
- export function destroyCurrentModal(outro: boolean = true): void {
51
- closeCurrentModal(outro)
52
-
53
- modals.pop()
54
- }
55
-
56
- export function destroyAllModals(outro: boolean = true): void {
57
- closeCurrentModal(outro)
58
-
59
- while (modals.length > 0) modals.pop()
60
- }
61
-
62
- /** @returns The modal before the currently active modal, if any */
63
- export function getPreviousModal(): Modal | null {
64
- return modals[modals.length - 2] || null
65
- }
66
-
67
- export function goBackToPreviousModal(): void {
68
- if (modals.length < 2) return
69
-
70
- destroyCurrentModal()
71
-
72
- // Get the previous modal from the array by removing it, we're re-adding it when calling openModal
73
- const previousModal = modals.pop()
74
- if (!previousModal) return
75
-
76
- openModal({ ...previousModal })
77
- }
78
-
79
- export function getAllModals(): Modal[] {
80
- return modals
81
- }
@@ -1,14 +0,0 @@
1
- export type ParticipantData = {
2
- sid: string
3
- name: string
4
- birth_date: string
5
- death_date: string | null
6
- jobs: Job[]
7
- image: string | null
8
- image_uuid: string | null
9
- gender: string
10
- character?: string | null
11
- bio?: string | null
12
- }
13
-
14
- export type Job = 'actor' | 'writer' | 'director'
@@ -1,17 +0,0 @@
1
- <script lang="ts">
2
- interface Props {
3
- direction?: 'left' | 'right'
4
- }
5
-
6
- const { direction = 'right' }: Props = $props()
7
- </script>
8
-
9
- <svg width="10" height="18" viewBox="0 0 10 18" class="{direction}">
10
- <path d="M94.55,59.274a1.517,1.517,0,0,0,0-2.157,1.535,1.535,0,0,0-2.157,0L87,62.509l-5.4-5.392a1.525,1.525,0,0,0-2.157,2.157l6.48,6.48a1.535,1.535,0,0,0,2.157,0Z" transform="translate(-56.054 95.5) rotate(-90)" fill="currentColor" stroke-width="1"/>
11
- </svg>
12
-
13
- <style lang="scss">
14
- .left {
15
- transform: rotate(180deg);
16
- }
17
- </style>
@@ -1,172 +0,0 @@
1
- <script lang="ts">
2
- import { playPilotBaseUrl } from '$lib/constants'
3
- import { t } from '$lib/localization'
4
- import { mergePlaylinks } from '$lib/playlink'
5
- import type { TitleData } from '$lib/types/title'
6
- import IconArrow from './Icons/IconArrow.svelte'
7
- import IconIMDb from './Icons/IconIMDb.svelte'
8
- import PlaylinkIcon from './PlaylinkIcon.svelte'
9
- import TitlePoster from './TitlePoster.svelte'
10
-
11
- interface Props {
12
- title: TitleData
13
- // eslint-disable-next-line no-unused-vars
14
- onclick?: (event: MouseEvent) => void
15
- }
16
-
17
- const { title, onclick = () => null }: Props = $props()
18
-
19
- const playlinks = $derived(mergePlaylinks(title.providers))
20
- const limitedPlaylinks = $derived(playlinks.slice(0, 3))
21
- </script>
22
-
23
- <a class="title" href="{playPilotBaseUrl}/{title.type}/{title.slug}" {onclick}>
24
- <div class="poster">
25
- <TitlePoster {title} width={28} height={42} />
26
- </div>
27
-
28
- <div class="content">
29
- <div class="heading">{title.title}</div>
30
-
31
- <div class="meta">
32
- <div class="imdb">
33
- <IconIMDb />
34
- {title.imdb_score}
35
- </div>
36
-
37
- <div>{title.year}</div>
38
- <div>{title.type}</div>
39
-
40
- {#if title.length}
41
- <div>{title.length} min</div>
42
- {/if}
43
- </div>
44
-
45
- <div class="playlinks">
46
- {#each limitedPlaylinks as playlink}
47
- <PlaylinkIcon {playlink} onclick={(event) => event.stopPropagation()} />
48
- {/each}
49
-
50
- {#if playlinks.length > limitedPlaylinks.length}
51
- <span class="more">
52
- +{playlinks.length - limitedPlaylinks.length}
53
- </span>
54
- {/if}
55
-
56
- {#if !playlinks.length}
57
- <div class="empty" data-testid="playlinks-empty">
58
- {t('Title Unavailable')}
59
- </div>
60
- {/if}
61
- </div>
62
- </div>
63
-
64
- <div class="action">
65
- <IconArrow />
66
- </div>
67
- </a>
68
-
69
- <style lang="scss">
70
- .title {
71
- appearance: none;
72
- display: flex;
73
- gap: margin(1);
74
- width: 100%;
75
- background: var(--playpilot-list-item-background, var(--playpilot-lighter));
76
- padding: margin(0.5);
77
- border: 0;
78
- border-radius: var(--playpilot-list-item-border-radius, margin(0.5));
79
- text-decoration: none;
80
- font-style: normal !important;
81
-
82
- &:hover {
83
- background: var(--playpilot-list-item-hover-background, var(--playpilot-content));
84
- }
85
-
86
- &:last-child {
87
- border-bottom: 0;
88
- }
89
- }
90
-
91
- .poster {
92
- flex: 0 0 auto;
93
- height: auto;
94
- align-self: start;
95
- width: margin(4);
96
- aspect-ratio: 28/42;
97
- border-radius: var(--playpilot-detail-image-border-radius, margin(0.5));
98
- background: var(--playpilot-detail-image-background, var(--playpilot-content));
99
- overflow: hidden;
100
- }
101
-
102
- .content {
103
- display: flex;
104
- flex-direction: column;
105
- font-family: inherit;
106
- text-align: left;
107
- color: var(--playpilot-list-item-text-color, var(--playpilot-text-color));
108
- font-size: var(--playpilot-detail-font-size, 14px);
109
- line-height: normal;
110
- }
111
-
112
- .heading {
113
- color: var(--playpilot-list-item-title-text-color, var(--playpilot-detail-title-text-color, var(--playpilot-text-color)));
114
- font-weight: var(--playpilot-list-item-title-font-weight, var(--playpilot-detail-title-font-weight, 500));
115
- }
116
-
117
- .meta {
118
- display: flex;
119
- flex-wrap: wrap;
120
- gap: 0 margin(0.5);
121
- margin: margin(0.25) 0 margin(0.5);
122
- font-size: var(--playpilot-detail-font-size-small, 12px);
123
- font-weight: var(--playpilot-list-item-meta-font-weight, var(--playpilot-detail-title-font-weight, 500));
124
- color: var(--playpilot-list-item-meta-text-color, var(--playpilot-text-color-alt));
125
-
126
- > div {
127
- text-transform: capitalize;
128
- }
129
- }
130
-
131
- .imdb {
132
- display: flex;
133
- align-items: center;
134
- gap: margin(0.25);
135
- }
136
-
137
- .playlinks {
138
- display: flex;
139
- flex-wrap: wrap;
140
- gap: margin(0.25);
141
- margin-top: auto;
142
- }
143
-
144
- .more {
145
- display: flex;
146
- align-items: center;
147
- padding: margin(0.25);
148
- color: var(--playpilot-list-item-more-text-color, var(--playpilot-text-color-alt));
149
- font-size: var(--playpilot-detail-font-size-small, 12px);
150
- }
151
-
152
- .empty {
153
- margin-top: margin(0.5);
154
- opacity: 0.65;
155
- font-style: italic;
156
- font-size: 0.85em;
157
- white-space: initial;
158
- }
159
-
160
- .action {
161
- display: flex;
162
- margin: 0 margin(0.5) 0 auto;
163
- padding-left: margin(0.5);
164
- align-self: center;
165
- color: var(--playpilot-list-item-action-color, var(--playpilot-detail-text-color, var(--playpilot-text-color-alt)));
166
-
167
- &:hover,
168
- &:active {
169
- color: var(--playpilot-list-item-action-hover-color, var(--playpilot-detail-text-color, var(--playpilot-text-color)));
170
- }
171
- }
172
- </style>
@@ -1,88 +0,0 @@
1
- <script lang="ts">
2
- import { heading } from '$lib/actions/heading'
3
- import { openModal } from '$lib/modal'
4
- import type { ParticipantData } from '$lib/types/participant'
5
- import ListTitle from './ListTitle.svelte'
6
-
7
- interface Props {
8
- participant: ParticipantData
9
- }
10
-
11
- const { participant }: Props = $props()
12
-
13
- const { name, birth_date, death_date } = $derived(participant)
14
-
15
- function formatDate(dateString: string): string {
16
- const date = new Date(dateString)
17
- return date.toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
18
- }
19
- </script>
20
-
21
- <div class="header">
22
- <div class="heading" use:heading={2} id="name">{name}</div>
23
-
24
- {#if birth_date}
25
- <p class="dates">
26
- Born on <strong>{formatDate(birth_date)}</strong>{#if death_date}, died on <strong>{formatDate(death_date)}</strong>{/if}
27
- </p>
28
- {/if}
29
- </div>
30
-
31
- <div class="content">
32
- <div class="heading small" use:heading={3} id="credits">Credits</div>
33
-
34
- <div class="list">
35
- {#each window.PlayPilotLinkInjections?.evaluated_link_injections?.map(i => i.title_details) || [] as title}
36
- {#if title}
37
- <ListTitle {title} onclick={(event) => openModal({ event, data: title })} />
38
- {/if}
39
- {/each}
40
- </div>
41
- </div>
42
-
43
- <style lang="scss">
44
- .header {
45
- padding: margin(4) margin(1) margin(2);
46
- background: linear-gradient(to bottom, var(--playpilot-detail-background-light, var(--playpilot-lighter)), transparent);
47
- border-radius: var(--playpilot-detail-border-radius, margin(1) margin(1) 0 0);
48
- font-family: var(--playpilot-detail-font-family, var(--playpilot-font-family));
49
- font-weight: var(--playpilot-detail-font-weight, normal);
50
- font-size: var(--playpilot-detail-font-size, 14px);
51
- line-height: var(--playpilot-participant-description-line-height, normal);
52
- color: var(--playpilot-detail-text-color, var(--playpilot-text-color));
53
- }
54
-
55
- .heading {
56
- margin: 0;
57
- font-family: var(--playpilot-detail-title-font-family, var(--playpilot-font-family));
58
- font-weight: var(--playpilot-detail-title-font-weight, lighter);
59
- font-size: var(--playpilot-detail-title-font-size, margin(1.5));
60
- line-height: normal;
61
- font-style: var(--playpilot-detail-title-font-style, normal);
62
-
63
- &.small {
64
- margin: 0 0 margin(0.5);
65
- font-size: var(--playpilot-detail-title-small-font-size, margin(1.25));
66
- }
67
- }
68
-
69
- .dates {
70
- margin: margin(0.5) 0 0;
71
- }
72
-
73
- .content {
74
- padding: 0 margin(1) margin(1);
75
- color: var(--playpilot-detail-text-color, var(--playpilot-text-color));
76
- font-family: var(--playpilot-detail-font-family, var(--playpilot-font-family));
77
- font-weight: var(--playpilot-detail-font-weight, normal);
78
- font-size: var(--playpilot-detail-font-size, 14px);
79
- line-height: normal;
80
- font-style: normal;
81
- }
82
-
83
- .list {
84
- display: flex;
85
- flex-direction: column;
86
- gap: margin(0.5);
87
- }
88
- </style>
@@ -1,30 +0,0 @@
1
-
2
- <script lang="ts">
3
- import Modal from './Modal.svelte'
4
- import Participant from './Participant.svelte'
5
- import type { ParticipantData } from '$lib/types/participant'
6
-
7
- interface Props {
8
- participant: ParticipantData
9
- }
10
-
11
- const { participant = {
12
- sid: 'pr5C5W',
13
- name: 'James Franco',
14
- birth_date: '1978-04-19',
15
- death_date: null,
16
- jobs: ['actor'],
17
- image: 'https://hips.hearstapps.com/hmg-prod/images/gettyimages-161098947-square.jpg',
18
- image_uuid: '08ed2fac357011eb87470aff12c0f5c9',
19
- gender: 'Male',
20
- bio: 'Aenean feugiat nec odio at venenatis. Integer porta neque metus, a sollicitudin dolor dapibus et. In sollicitudin nulla eget ultricies porttitor. Nulla facilisi. Sed turpis orci, facilisis efficitur neque in, ultrices ultricies purus. Mauris nec augue a nisi imperdiet semper ut nec tellus. Donec at tristique odio. Etiam luctus eget metus non mattis. Integer imperdiet in elit eu varius. Donec ornare, nibh vitae accumsan consequat, lacus nulla elementum sapien, a scelerisque tellus augue ac erat. Aenean finibus fringilla magna, ac laoreet nisl convallis vel. Proin laoreet ex ac augue maximus, nec gravida tortor pharetra.\nCurabitur maximus dui sed risus placerat pharetra vitae ut orci. Proin sodales enim a elit euismod, a varius sem suscipit. Vivamus eu magna cursus, fringilla est in, mollis nunc. Mauris fringilla eleifend nibh, eget auctor lectus bibendum non. Praesent sed elit ipsum. Donec nunc dolor, sagittis hendrerit gravida et, lacinia sed metus. Morbi tempus mi massa. In hac habitasse platea dictumst. Suspendisse aliquet tincidunt lectus ut elementum.',
21
- } }: Props = $props()
22
-
23
- let windowWidth = $state(0)
24
- </script>
25
-
26
- <svelte:window bind:innerWidth={windowWidth} />
27
-
28
- <Modal closeButtonStyle="flat">
29
- <Participant {participant} />
30
- </Modal>
@@ -1,41 +0,0 @@
1
- <script lang="ts">
2
- import { removeImageUrlPrefix } from '$lib/image'
3
- import type { PlaylinkData } from '$lib/types/playlink'
4
-
5
- interface Props {
6
- playlink: PlaylinkData
7
- size?: number
8
- // eslint-disable-next-line no-unused-vars
9
- onclick?: (event: MouseEvent) => void
10
- }
11
-
12
- const { playlink, size = 40, onclick = () => null }: Props = $props()
13
-
14
- const { name, url, logo_url } = $derived(playlink)
15
- </script>
16
-
17
- <a href={url} target="_blank" class="playlink" data-playlink={name} rel="sponsored" aria-label={name} {onclick}>
18
- <img src={removeImageUrlPrefix(logo_url)} alt="" height={size} width={size} />
19
- </a>
20
-
21
- <style lang="scss">
22
- .playlink {
23
- display: inline-block;
24
- background: var(--playpilot-playlink-background, var(--playpilot-light));
25
- border-radius: var(--playpilot-playlink-border-radius, margin(0.5));
26
- overflow: hidden;
27
-
28
- &:hover,
29
- &:active {
30
- filter: var(--playpilot-playlink-hover-filter, brightness(1.1));
31
- background: var(--playpilot-playlink-hover-background, var(--playpilot-playlink-background, var(--playpilot-lighter))) !important;
32
- text-decoration: none !important;
33
- outline: 2px solid var(--playpilot-detail-text-color, var(--playpilot-text-color));
34
- }
35
-
36
- img {
37
- display: block;
38
- margin: 0;
39
- }
40
- }
41
- </style>
@@ -1,56 +0,0 @@
1
- <script lang="ts">
2
- import { openModal } from '$lib/modal'
3
- import type { ParticipantData } from '$lib/types/participant'
4
- import Rail from './Rail.svelte'
5
-
6
- interface Props {
7
- participants: ParticipantData[]
8
- }
9
-
10
- const { participants }: Props = $props()
11
- </script>
12
-
13
- <Rail heading="Cast">
14
- {#each participants.slice(0, 15) as participant}
15
- <button class="participant" onclick={event => openModal({ event, type: 'participant', data: participant })}>
16
- <span class="truncate">{participant.name}</span>
17
-
18
- <div class="character truncate">{participant.character}</div>
19
- </button>
20
- {/each}
21
- </Rail>
22
-
23
- <style lang="scss">
24
- .participant {
25
- display: block;
26
- flex: 0 0 10rem;
27
- width: 10rem;
28
- padding: margin(0.5);
29
- border: 0;
30
- border-radius: var(--playpilot-cast-border-radius, var(--playpilot-playlink-border-radius, margin(0.5)));
31
- background: var(--playpilot-cast-background, var(--playpilot-playlink-background, var(--playpilot-lighter)));
32
- cursor: pointer;
33
- font-family: inherit;
34
- text-align: left;
35
- color: inherit;
36
- font-size: var(--playpilot-cast-font-size, var(--playpilot-playlinks-font-size, margin(0.75)));
37
- white-space: nowrap;
38
-
39
- &:hover,
40
- &:active {
41
- filter: var(--playpilot-cast-hover-filter, var(--playpilot-playlink-hover-filter, brightness(1.1)));
42
- text-decoration: none !important;
43
- }
44
- }
45
-
46
- .character {
47
- color: var(--playpilot-cast-character-text-color, var(--playpilot-text-color-alt));
48
- font-style: italic;
49
- }
50
-
51
- .truncate {
52
- overflow: hidden;
53
- text-overflow: ellipsis;
54
- white-space: nowrap;
55
- }
56
- </style>