@playpilot/tpi 5.33.0-beta.explore.6 → 5.33.0-beta.in-text.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 (50) hide show
  1. package/dist/link-injections.js +10 -10
  2. package/package.json +1 -1
  3. package/src/lib/api/ads.ts +1 -1
  4. package/src/lib/api/titles.ts +1 -13
  5. package/src/lib/color.ts +19 -0
  6. package/src/lib/data/translations.ts +0 -5
  7. package/src/lib/enums/SplitTest.ts +5 -0
  8. package/src/lib/fakeData.ts +0 -1
  9. package/src/lib/injection.ts +41 -0
  10. package/src/lib/modal.ts +6 -7
  11. package/src/lib/scss/global.scss +41 -0
  12. package/src/lib/types/config.d.ts +0 -12
  13. package/src/lib/types/title.d.ts +1 -4
  14. package/src/routes/+page.svelte +9 -8
  15. package/src/routes/components/Ads/TopScroll.svelte +18 -4
  16. package/src/routes/components/Debugger.svelte +8 -0
  17. package/src/routes/components/Icons/IconClose.svelte +1 -9
  18. package/src/routes/components/ListTitle.svelte +8 -7
  19. package/src/routes/components/Modal.svelte +24 -6
  20. package/src/routes/components/Share.svelte +23 -5
  21. package/src/routes/components/Title.svelte +22 -22
  22. package/src/routes/components/TitleModal.svelte +1 -4
  23. package/src/routes/elements/+page.svelte +2 -39
  24. package/src/tests/lib/api/ads.test.js +1 -0
  25. package/src/tests/routes/components/Share.test.js +12 -12
  26. package/src/tests/routes/components/Title.test.js +0 -13
  27. package/src/lib/explore.ts +0 -59
  28. package/src/lib/images/titles-list.webp +0 -0
  29. package/src/lib/trailer.ts +0 -22
  30. package/src/lib/types/api.d.ts +0 -6
  31. package/src/routes/components/Button.svelte +0 -73
  32. package/src/routes/components/Explore/Explore.svelte +0 -191
  33. package/src/routes/components/Explore/ExploreCallToAction.svelte +0 -58
  34. package/src/routes/components/Explore/ExploreModal.svelte +0 -15
  35. package/src/routes/components/Explore/Filter.svelte +0 -3
  36. package/src/routes/components/Explore/Search.svelte +0 -56
  37. package/src/routes/components/Icons/IconPlay.svelte +0 -3
  38. package/src/routes/components/Icons/IconSearch.svelte +0 -3
  39. package/src/routes/components/ListTitleSkeleton.svelte +0 -42
  40. package/src/routes/components/Trailer.svelte +0 -18
  41. package/src/routes/components/YouTubeEmbedOverlay.svelte +0 -96
  42. package/src/routes/explore/+page.svelte +0 -61
  43. package/src/tests/lib/api/titles.test.js +0 -55
  44. package/src/tests/lib/explore.test.js +0 -139
  45. package/src/tests/lib/trailer.test.js +0 -56
  46. package/src/tests/routes/components/Button.test.js +0 -28
  47. package/src/tests/routes/components/Explore/Explore.test.js +0 -133
  48. package/src/tests/routes/components/Explore/Search.test.js +0 -26
  49. package/src/tests/routes/components/Trailer.test.js +0 -20
  50. package/src/tests/routes/components/YouTubeEmbedOverlay.test.js +0 -31
@@ -7,7 +7,6 @@
7
7
  import SimilarRail from './Rails/SimilarRail.svelte'
8
8
  import TitlePoster from './TitlePoster.svelte'
9
9
  import Share from './Share.svelte'
10
- import Trailer from './Trailer.svelte'
11
10
  import { t } from '$lib/localization'
12
11
  import type { TitleData } from '$lib/types/title'
13
12
  import { heading } from '$lib/actions/heading'
@@ -37,28 +36,26 @@
37
36
 
38
37
  <div class="heading" use:heading={2} class:truncate={small} id="title">{title.title}</div>
39
38
 
40
- <div class="info">
41
- <div class="imdb">
42
- <IconIMDb />
43
- {title.imdb_score}
44
- </div>
39
+ <div class="row">
40
+ <div class="info">
41
+ <div class="imdb">
42
+ <IconIMDb />
43
+ {title.imdb_score}
44
+ </div>
45
45
 
46
- <Genres genres={title.genres} />
46
+ <Genres genres={title.genres} />
47
47
 
48
- <div>{title.year}</div>
49
- <div class="capitalize">{t(`Type: ${title.type}`)}</div>
48
+ <div>{title.year}</div>
49
+ <div class="capitalize">{t(`Type: ${title.type}`)}</div>
50
50
 
51
- {#if !small && title.length}
52
- <div>{title.length} {t('Minutes')}</div>
53
- {/if}
54
- </div>
51
+ {#if !small && title.length}
52
+ <div>{title.length} {t('Minutes')}</div>
53
+ {/if}
54
+ </div>
55
55
 
56
- <div class="actions">
57
- <!-- !! Button is temporarily always visible while embeddable_url is not yet available -->
58
- {#if true || title.embeddable_url}
59
- <Trailer title={title} />
56
+ <div class="action">
60
57
  <Share title={title.title} url={titleUrl(title)} />
61
- {/if}
58
+ </div>
62
59
  </div>
63
60
  </div>
64
61
 
@@ -149,6 +146,11 @@
149
146
  }
150
147
  }
151
148
 
149
+ .row {
150
+ display: flex;
151
+ align-items: flex-start;
152
+ }
153
+
152
154
  .info {
153
155
  display: flex;
154
156
  flex-wrap: wrap;
@@ -180,10 +182,8 @@
180
182
  }
181
183
  }
182
184
 
183
- .actions {
184
- display: flex;
185
- gap: margin(0.5);
186
- margin-top: margin(0.5);
185
+ .action {
186
+ margin: margin(-0.125) 0 0 auto;
187
187
  }
188
188
 
189
189
  .background {
@@ -8,7 +8,6 @@
8
8
  import Title from './Title.svelte'
9
9
  import TopScroll from './Ads/TopScroll.svelte'
10
10
  import Display from './Ads/Display.svelte'
11
- import ExploreCallToAction from './Explore/ExploreCallToAction.svelte'
12
11
 
13
12
  interface Props {
14
13
  title: TitleData
@@ -41,8 +40,6 @@
41
40
  {#snippet bubble()}
42
41
  {#if topScrollAd}
43
42
  <TopScroll campaign={topScrollAd} />
44
- {:else}
45
- <ExploreCallToAction />
46
43
  {/if}
47
44
  {/snippet}
48
45
 
@@ -52,6 +49,6 @@
52
49
  {/if}
53
50
  {/snippet}
54
51
 
55
- <Modal {onscroll} {initialScrollPosition} {bubble} prepend={displayAd ? prepend : null} tall>
52
+ <Modal {onscroll} {initialScrollPosition} prepend={displayAd ? prepend : null} bubble={topScrollAd ? bubble : null} tall>
56
53
  <Title {title} />
57
54
  </Modal>
@@ -2,7 +2,6 @@
2
2
  import { browser } from '$app/environment'
3
3
  import { title, linkInjections, campaign, participants } from '$lib/fakeData'
4
4
  import { openModal } from '$lib/modal'
5
- import { insertExplore, insertExploreIntoNavigation } from '$lib/explore'
6
5
  import Disclaimer from '../components/Ads/Disclaimer.svelte'
7
6
  import Display from '../components/Ads/Display.svelte'
8
7
  import TopScroll from '../components/Ads/TopScroll.svelte'
@@ -17,22 +16,9 @@
17
16
  import Title from '../components/Title.svelte'
18
17
  import TitlePopover from '../components/TitlePopover.svelte'
19
18
  import Tooltip from '../components/Tooltip.svelte'
20
- import Explore from '../components/Explore/Explore.svelte'
21
-
22
- if (browser) {
23
- // @ts-ignore
24
- window.PlayPilotLinkInjections = {
25
- token: 'ZoAL14yqzevMyQiwckbvyetOkeIUeEDN',
26
- config: {
27
- explore_navigation_selector: 'nav a:last-child',
28
- explore_navigation_label: 'Streaming guide',
29
- explore_navigation_path: '/explore',
30
- },
31
- }
32
- }
33
19
 
34
- // Used to re-render some elements with a key
35
- let renderKey = Math.random()
20
+ // @ts-ignore
21
+ if (browser) window.PlayPilotLinkInjections = {}
36
22
  </script>
37
23
 
38
24
  <h1>Elements</h1>
@@ -167,29 +153,6 @@
167
153
  </div>
168
154
  </div>
169
155
 
170
- <h2>Explore</h2>
171
-
172
- <div class="group">
173
- <div class="item">
174
- <button onclick={() => renderKey = Math.random()}>Rerender</button>
175
-
176
- {#key renderKey}
177
- <Explore />
178
- {/key}
179
- </div>
180
-
181
- <div class="item">
182
- <button onclick={() => openModal({ type: 'explore' })}>Show explore modal</button>
183
- </div>
184
-
185
- <div class="item">
186
- <button onclick={insertExplore}>Insert explore component</button>
187
- <button onclick={insertExploreIntoNavigation}>Insert explore into navigation</button>
188
-
189
- <div data-playpilot-explore style="height: 20rem"></div>
190
- </div>
191
- </div>
192
-
193
156
  <style lang="scss">
194
157
  @import url('$lib/scss/global.scss');
195
158
 
@@ -10,6 +10,7 @@ vi.mock('$lib/api/api', () => ({
10
10
  api: vi.fn(),
11
11
  }))
12
12
 
13
+
13
14
  vi.mock('$lib/tracking', () => ({
14
15
  track: vi.fn(),
15
16
  }))
@@ -16,57 +16,57 @@ vi.mock('$lib/tracking', () => ({
16
16
 
17
17
  describe('Share.svelte', () => {
18
18
  it('Should open context menu on click', async () => {
19
- const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
19
+ const { getByLabelText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
20
20
 
21
21
  expect(queryByText('Copy URL')).not.toBeTruthy()
22
22
  expect(queryByText('Email')).not.toBeTruthy()
23
23
 
24
- await fireEvent.click(getByText('Share'))
24
+ await fireEvent.click(getByLabelText('Share'))
25
25
 
26
26
  expect(queryByText('Copy URL')).toBeTruthy()
27
27
  expect(queryByText('Email')).toBeTruthy()
28
28
  })
29
29
 
30
30
  it('Should close context menu on click of items', async () => {
31
- const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
31
+ const { getByLabelText, getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
32
32
 
33
- await fireEvent.click(getByText('Share'))
33
+ await fireEvent.click(getByLabelText('Share'))
34
34
  await fireEvent.click(getByText('Copy URL'))
35
35
 
36
36
  expect(queryByText('Copy URL')).not.toBeTruthy()
37
37
  })
38
38
 
39
39
  it('Should close context menu on click of body', async () => {
40
- const { getByText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
40
+ const { getByLabelText, queryByText } = render(Share, { title: 'Some title', url: 'some-url' })
41
41
 
42
- await fireEvent.click(getByText('Share'))
42
+ await fireEvent.click(getByLabelText('Share'))
43
43
  await fireEvent.click(document.body)
44
44
 
45
45
  expect(queryByText('Copy URL')).not.toBeTruthy()
46
46
  })
47
47
 
48
48
  it('Should fire copyToClipboard on click of button', async () => {
49
- const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
49
+ const { getByLabelText, getByText } = render(Share, { title: 'Some title', url: 'some-url' })
50
50
 
51
- await fireEvent.click(getByText('Share'))
51
+ await fireEvent.click(getByLabelText('Share'))
52
52
  await fireEvent.click(getByText('Copy URL'))
53
53
 
54
54
  expect(copyToClipboard).toHaveBeenCalledWith('some-url?utm_source=tpi')
55
55
  })
56
56
 
57
57
  it('Should fire track function on click of copy URL button', async () => {
58
- const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
58
+ const { getByLabelText, getByText } = render(Share, { title: 'Some title', url: 'some-url' })
59
59
 
60
- await fireEvent.click(getByText('Share'))
60
+ await fireEvent.click(getByLabelText('Share'))
61
61
  await fireEvent.click(getByText('Copy URL'))
62
62
 
63
63
  expect(track).toHaveBeenCalledWith(TrackingEvent.ShareTitle, null, { title: 'Some title', url: 'http://localhost:3000/', method: 'copy' })
64
64
  })
65
65
 
66
66
  it('Should fire track function on click of email button', async () => {
67
- const { getByText } = render(Share, { title: 'Some title', url: 'some-url' })
67
+ const { getByLabelText, getByText } = render(Share, { title: 'Some title', url: 'some-url' })
68
68
 
69
- await fireEvent.click(getByText('Share'))
69
+ await fireEvent.click(getByLabelText('Share'))
70
70
  await fireEvent.click(getByText('Email'))
71
71
 
72
72
  expect(track).toHaveBeenCalledWith(TrackingEvent.ShareTitle, null, { title: 'Some title', url: 'http://localhost:3000/', method: 'email' })
@@ -91,17 +91,4 @@ describe('Title.svelte', () => {
91
91
  expect(fetchParticipantsForTitle).toHaveBeenCalled()
92
92
  expect(fetchSimilarTitles).toHaveBeenCalled()
93
93
  })
94
-
95
- it('Should show trailer button when embeddable_url is given', () => {
96
- const { getByText } = render(Title, { title: { ...title, embeddable_url: 'some-url' } })
97
-
98
- expect(getByText('Watch trailer')).toBeTruthy()
99
- })
100
-
101
- // Temporarily disabled while button is always visible
102
- // it('Should not show trailer button when embeddable_url is not given', () => {
103
- // const { queryByText } = render(Title, { title })
104
-
105
- // expect(queryByText('Watch Trailer')).not.toBeTruthy()
106
- // })
107
94
  })
@@ -1,59 +0,0 @@
1
- import { mount, unmount } from 'svelte'
2
- import Explore from '../routes/components/Explore/Explore.svelte'
3
-
4
- export const exploreParentSelector = `[data-playpilot-explore]`
5
-
6
- let exploreInsertedComponent: object | null = null
7
-
8
- /**
9
- * Insert the Explore component inside of the needed selector. If no element is found, do nothing.
10
- * Only one Explore component can exist per page.
11
- */
12
- export function insertExplore(): void {
13
- const target = document.querySelector<HTMLElement>(exploreParentSelector)
14
- if (!target) return
15
-
16
- destroyExplore()
17
-
18
- target.innerHTML = ''
19
- exploreInsertedComponent = mount(Explore, { target })
20
- }
21
-
22
- export function destroyExplore(): void {
23
- if (!exploreInsertedComponent) return
24
-
25
- unmount(exploreInsertedComponent)
26
- exploreInsertedComponent = null
27
- }
28
-
29
- /**
30
- * Copy over an existing element on the page given by the selector. This will link to a page that is
31
- * set up by the third party to hold the explore component.
32
- * @returns Whether or not the component was succesfully inserted
33
- */
34
- export function insertExploreIntoNavigation(): boolean {
35
- const config = window.PlayPilotLinkInjections.config
36
- if (!config) return false
37
-
38
- const { explore_navigation_selector: selector, explore_navigation_label: label, explore_navigation_path: path, explore_navigation_insert_position: insertPosition } = window.PlayPilotLinkInjections.config
39
- if (!selector) return false
40
-
41
- // Make sure to remove an element we created if it already exists. Should not be possible under normal circumstances.
42
- document.querySelector('[data-playpilot-explore-navigation-element]')?.remove()
43
-
44
- const navigationElement = document.querySelector<HTMLElement>(selector)
45
- if (!navigationElement) return false
46
-
47
- const copiedElement = navigationElement.cloneNode(true) as HTMLElement
48
- const linkElement = (copiedElement.nodeName === 'A' ? copiedElement : copiedElement.querySelector('a')) as HTMLLinkElement
49
-
50
- linkElement.classList.remove('active')
51
- linkElement.innerText = label || 'Streaming Guide'
52
- linkElement.href = path
53
-
54
- copiedElement.dataset.playpilotExploreNavigationElement = 'true'
55
-
56
- navigationElement.insertAdjacentElement(insertPosition || 'afterend', copiedElement)
57
-
58
- return true
59
- }
Binary file
@@ -1,22 +0,0 @@
1
- import { mount, unmount } from "svelte"
2
- import { getPlayPilotWrapperElement } from "./injection"
3
- import type { TitleData } from "./types/title"
4
- import YouTubeEmbedOverlay from "../routes/components/YouTubeEmbedOverlay.svelte"
5
-
6
- let currentTrailerComponent: object | null = {}
7
-
8
- export function openTrailerOverlay(title: TitleData) {
9
- const target = getPlayPilotWrapperElement()
10
- // !! Temporarily falls back to a placeholder is while embeddable_url is not yet present
11
- const props = { onclose: closeTrailerOverlay, embeddable_url: title.embeddable_url || 'https://www.youtube.com/watch?v=xGTq0blCPVQ' }
12
-
13
- currentTrailerComponent = mount(YouTubeEmbedOverlay, { target, props })
14
- }
15
-
16
- export function closeTrailerOverlay(): void {
17
- if (!currentTrailerComponent) return
18
-
19
- unmount(currentTrailerComponent, { outro: true })
20
-
21
- currentTrailerComponent = null
22
- }
@@ -1,6 +0,0 @@
1
- export type APIPaginatedResult<T> = {
2
- next: string | null
3
- previous: string | null
4
- results: T[]
5
- count?: number
6
- }
@@ -1,73 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte'
3
-
4
- interface Props {
5
- variant?: 'filled' | 'border'
6
- size?: 'base' | 'large'
7
- active?: boolean
8
- // eslint-disable-next-line no-unused-vars
9
- onclick?: (event: MouseEvent) => void
10
- children?: Snippet
11
- }
12
-
13
- const { variant = 'filled', size = 'base', active = false, onclick, children }: Props = $props()
14
- </script>
15
-
16
- <button class="button {variant} {size}" class:active {onclick}>
17
- {@render children?.()}
18
- </button>
19
-
20
- <style lang="scss">
21
- .button {
22
- appearance: none;
23
- display: flex;
24
- height: 100%;
25
- align-items: center;
26
- justify-content: center;
27
- gap: margin(0.25);
28
- border: 0;
29
- padding: 0.25em 0.5em;
30
- background: transparent;
31
- border-radius: theme(button-border-radius, border-radius);
32
- color: theme(button-text-color, text-color-alt);
33
- font-size: inherit;
34
- font-family: inherit;
35
- font-weight: theme(button-font-weight, normal);
36
- cursor: pointer;
37
-
38
- :global(svg) {
39
- width: 1.5em;
40
- height: 1.5em;
41
- opacity: 0.75;
42
- }
43
- }
44
-
45
- .filled {
46
- background: theme(button-filled-background, content);
47
-
48
- &:hover,
49
- &:active {
50
- background: theme(button-filled-hover-background, content-light);
51
- color: theme(button-filled-hover-text-color, text-color);
52
- }
53
-
54
- &.active {
55
- box-shadow: inset 0 0 0 1px currentColor;
56
- }
57
- }
58
-
59
- .border {
60
- box-shadow: inset 0 0 0 1px theme(button-border-color, content-light);
61
-
62
- &:hover,
63
- &:active {
64
- background: theme(button-border-color, content);
65
- color: theme(button-hover-text-color, text-color);
66
- }
67
- }
68
-
69
- .large {
70
- padding: 0.5em 1.5em;
71
- }
72
- </style>
73
-
@@ -1,191 +0,0 @@
1
- <script lang="ts">
2
- import { heading } from '$lib/actions/heading'
3
- import { searchTitles } from '$lib/api/search'
4
- import { fetchTitles } from '$lib/api/titles'
5
- import { exploreParentSelector } from '$lib/explore'
6
- import { openModal } from '$lib/modal'
7
- import type { APIPaginatedResult } from '$lib/types/api'
8
- import type { ContentType, TitleData } from '$lib/types/title'
9
- import Button from '../Button.svelte'
10
- import ListTitle from '../ListTitle.svelte'
11
- import ListTitleSkeleton from '../ListTitleSkeleton.svelte'
12
- import Filter from './Filter.svelte'
13
- import Search from './Search.svelte'
14
-
15
- type ExploreFilter = {
16
- content_type?: ContentType
17
- }
18
-
19
- const filter: ExploreFilter = $state({})
20
-
21
- let element: HTMLElement | null = null
22
- let titles: TitleData[] = $state([])
23
- let page = 1
24
- let searchQuery = ''
25
- let debounce: ReturnType<typeof setTimeout> | null = null
26
- let promise = $state(getTitlesForFilter())
27
- let height: string | null = $state(null)
28
-
29
- $effect(() => {
30
- // Set the height of this element to match that of it's container. That way we can
31
- // allow our element to be scrollable, rather than the parent needing to be scrollable.
32
- height = element?.closest<HTMLElement>(exploreParentSelector)?.style.height || null
33
- })
34
-
35
- async function getTitlesForFilter(): Promise<APIPaginatedResult<TitleData>> {
36
- let response
37
-
38
- // If a search query is given we use searchTitles with just the query.
39
- // If not, we use fetchTitles with the given params for the filter.
40
- // This is because the backend does not support filters for search results yet.
41
- // In the future we will likely merge these two, either by adding filters in the backend
42
- // or by filtering results in the frontend (this seems like the less good option).
43
- if (searchQuery) {
44
- const results: TitleData[] = await searchTitles(searchQuery)
45
- response = { results, next: null, previous: null }
46
-
47
- titles = results
48
- } else {
49
- const params = { page_size: 24, page, ...filter }
50
-
51
- response = await fetchTitles(params)
52
- if (!response?.results) throw new Error('Something went wrong when fetching titles in Explore')
53
-
54
- titles = [...titles, ...response.results]
55
- }
56
-
57
- return response
58
- }
59
-
60
- async function search(query: string): Promise<void> {
61
- searchQuery = query
62
-
63
- if (debounce) clearTimeout(debounce)
64
-
65
- debounce = setTimeout(() => {
66
- resetTitles()
67
- promise = getTitlesForFilter()
68
- }, 100)
69
- }
70
-
71
- function setFilter(key: keyof ExploreFilter, value: any): void {
72
- // If the value was previous present in the filter and a falsey value is given we remove it from
73
- // the filter entirely so it will no longer be used as a param
74
- if (!value && (key in filter)) {
75
- delete filter[key]
76
- } else if (value) {
77
- filter[key] = value
78
- }
79
-
80
- resetTitles()
81
- promise = getTitlesForFilter()
82
- }
83
-
84
- function resetTitles(): void {
85
- page = 1
86
- titles = []
87
- }
88
-
89
- function fetchMoreTitles(): void {
90
- page++
91
- promise = getTitlesForFilter()
92
- }
93
- </script>
94
-
95
- <div class="explore playpilot-styled-scrollbar" bind:this={element} style:height>
96
- <div class="header" role="banner">
97
- <div class="heading" use:heading>
98
- <strong>Site Name</strong>
99
- <div class="divider"></div>
100
- Streaming Guide
101
- </div>
102
-
103
- <div class="categories" role="navigation">
104
- <Button size="large" active={!filter.content_type} onclick={() => setFilter('content_type', '')}>All</Button>
105
- <Button size="large" active={filter.content_type === 'movie'} onclick={() => setFilter('content_type', 'movie')}>Movies</Button>
106
- <Button size="large" active={filter.content_type === 'series'} onclick={() => setFilter('content_type', 'series')}>Shows</Button>
107
- </div>
108
-
109
- <Search oninput={search} />
110
- <Filter />
111
- </div>
112
-
113
- <div class="titles" role="main">
114
- {#each titles as title}
115
- <ListTitle {title} onclick={(event) => openModal({ event, data: title })} />
116
- {/each}
117
-
118
- {#await promise}
119
- {#each { length: 12 } as _}
120
- <ListTitleSkeleton />
121
- {/each}
122
- {:then { next }}
123
- {#if next}
124
- <div class="show-more">
125
- <Button size="large" onclick={fetchMoreTitles}>Show more</Button>
126
- </div>
127
- {/if}
128
- {:catch}
129
- Something went wrong
130
- {/await}
131
- </div>
132
- </div>
133
-
134
- <style lang="scss">
135
- .explore {
136
- background: theme(explore-background, light);
137
- border-radius: theme(border-radius-large);
138
- max-width: 600px;
139
- margin: 0 auto;
140
- padding: margin(1);
141
- overflow: auto;
142
- font-family: theme(font-family);
143
- font-family: theme(detail-font-family, font-family);
144
- font-weight: theme(detail-font-weight, normal);
145
- font-size: theme(detail-font-size, font-size-base);
146
- }
147
-
148
- .header {
149
- display: flex;
150
- flex-direction: column;
151
- gap: margin(0.5);
152
- margin-bottom: margin(2);
153
- }
154
-
155
- .heading {
156
- display: flex;
157
- justify-content: center;
158
- gap: margin(0.5);
159
- margin: margin(1) 0;
160
- color: theme(text-color);
161
- }
162
-
163
- .divider {
164
- width: 2px;
165
- height: 0.5lh;
166
- margin-top: 0.25lh;
167
- background: currentColor;
168
- }
169
-
170
- .categories {
171
- display: grid;
172
- grid-template-columns: repeat(3, 1fr);
173
- gap: margin(0.5);
174
- }
175
-
176
- .titles {
177
- --playpilot-list-item-padding: 0;
178
- --playpilot-list-item-background: transparent;
179
- --playpilot-list-item-hover-shadow: 0 0 0 #{margin(0.25)} #{theme(lighter)};
180
- --playpilot-detail-image-background: #{theme(content)};
181
- display: flex;
182
- flex-direction: column;
183
- gap: margin(0.5);
184
- }
185
-
186
- .show-more {
187
- flex: 0 0 100%;
188
- display: grid;
189
- margin-top: margin(0.5);
190
- }
191
- </style>
@@ -1,58 +0,0 @@
1
- <script lang="ts">
2
- import IconArrow from '../Icons/IconArrow.svelte'
3
- import ImageTitlesList from '$lib/images/titles-list.webp'
4
- import { openModal } from '$lib/modal'
5
- </script>
6
-
7
- <button class="call-to-action" onclick={() => openModal({ type: 'explore' })}>
8
- <img src={ImageTitlesList} alt="" width="70" height="57" />
9
-
10
- <div>
11
- <strong>Looking for something else?</strong>
12
- <div>Use our streamingguide</div>
13
- </div>
14
-
15
- <div class="arrow">
16
- <IconArrow />
17
- </div>
18
- </button>
19
-
20
- <style lang="scss">
21
- strong {
22
- color: theme(text-color);
23
- font-size: theme(font-size-base);
24
- font-weight: normal;
25
- }
26
-
27
- .call-to-action {
28
- appearance: none;
29
- display: flex;
30
- align-items: center;
31
- gap: margin(1);
32
- width: 100%;
33
- padding: margin(1);
34
- border: 0;
35
- border-radius: theme(border-radius-large) theme(border-radius-large) 0 0;
36
- background: theme(light);
37
- font-family: theme(font-family);
38
- color: theme(text-color-alt);
39
- font-size: theme(font-size-small);
40
- line-height: 1.5;
41
- text-align: left;
42
- cursor: pointer;
43
-
44
- &:hover {
45
- filter: brightness(theme(hover-filter-brightness));
46
- }
47
- }
48
-
49
- .arrow {
50
- margin-left: auto;
51
-
52
- :global(svg) {
53
- display: block;
54
- height: margin(1.25);
55
- width: auto;
56
- }
57
- }
58
- </style>