@playpilot/tpi 5.6.0 → 5.7.0-beta.display-2
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/dist/link-injections.js +10 -10
- package/events.md +6 -0
- package/package.json +1 -1
- package/src/lib/ads.ts +38 -0
- package/src/lib/constants.ts +2 -1
- package/src/lib/enums/ImageDimensions.ts +7 -0
- package/src/lib/enums/SplitTest.ts +14 -1
- package/src/lib/enums/TrackingEvent.ts +3 -0
- package/src/lib/image.ts +12 -0
- package/src/lib/types/campaign.d.ts +45 -0
- package/src/lib/types/playlink.d.ts +2 -0
- package/src/lib/types/script.d.ts +2 -0
- package/src/main.ts +1 -0
- package/src/routes/+page.svelte +3 -0
- package/src/routes/components/Ads/Display.svelte +140 -0
- package/src/routes/components/Ads/TopScroll.svelte +240 -0
- package/src/routes/components/Modal.svelte +104 -19
- package/src/routes/components/Playlink.svelte +185 -0
- package/src/routes/components/Playlinks.svelte +34 -168
- package/src/routes/components/Popover.svelte +30 -2
- package/src/routes/components/Title.svelte +1 -0
- package/src/routes/components/TitleModal.svelte +23 -1
- package/src/routes/components/TitlePopover.svelte +11 -1
- package/src/tests/lib/ads.test.js +55 -0
- package/src/tests/routes/+page.test.js +33 -0
- package/src/tests/routes/components/Ads/Display.test.js +109 -0
- package/src/tests/routes/components/Ads/TopScroll.test.js +104 -0
- package/src/tests/routes/components/Playlink.test.js +95 -0
- package/src/tests/routes/components/Playlinks.test.js +0 -30
- package/src/tests/routes/components/TitleModal.test.js +36 -0
- package/src/tests/routes/components/TitlePopover.test.js +20 -0
package/events.md
CHANGED
|
@@ -66,3 +66,9 @@ Event | Action | Info | Payload
|
|
|
66
66
|
--- | --- | --- | ---
|
|
67
67
|
`ali_split_test_view` | _Should be fired for any active split test_ | | `key`, `variant` (a whole number starting at 0)
|
|
68
68
|
`ali_split_test_action` | _Should be fired for any assertion in split tests_ | | `key` (matches the key of `ali_split_test_view`), `variant` (a whole number starting at 0), `action`
|
|
69
|
+
|
|
70
|
+
### Ads
|
|
71
|
+
Event | Action | Info | Payload
|
|
72
|
+
--- | --- | --- | ---
|
|
73
|
+
`ali_top_scroll_click` | _Fired any time the top scroll ad is called_ | | `campaign_name`
|
|
74
|
+
`ali_display_ad_click` | _Fired any time the top scroll ad is clicked_ | | `campaign_name`
|
package/package.json
CHANGED
package/src/lib/ads.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getApiToken } from "./api"
|
|
2
|
+
import { apiBaseUrl } from "./constants"
|
|
3
|
+
import type { Campaign, CampaignFormat } from "./types/campaign"
|
|
4
|
+
import type { PlaylinkData } from "./types/playlink"
|
|
5
|
+
|
|
6
|
+
export async function fetchAds() {
|
|
7
|
+
const headers = new Headers({ 'Content-Type': 'application/json' })
|
|
8
|
+
const apiToken = getApiToken()
|
|
9
|
+
|
|
10
|
+
if (!apiToken) throw new Error('No token was provided')
|
|
11
|
+
|
|
12
|
+
const response = await fetch(apiBaseUrl + `/ads/browse/?region=nl&api-token=${apiToken}`, { headers })
|
|
13
|
+
|
|
14
|
+
if (!response.ok) throw response
|
|
15
|
+
|
|
16
|
+
const parsed = await response.json()
|
|
17
|
+
|
|
18
|
+
return parsed
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getFirstAdOfType(format: CampaignFormat): Campaign | null {
|
|
22
|
+
return (window.PlayPilotLinkInjections?.ads || []).find(i => i.campaign_format === format) || null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function campaignToPlaylink(campaign: Campaign): PlaylinkData {
|
|
26
|
+
return {
|
|
27
|
+
sid: '',
|
|
28
|
+
name: campaign.content.header || '',
|
|
29
|
+
url: campaign.cta.url || '',
|
|
30
|
+
logo_url: campaign.cta.image || '',
|
|
31
|
+
highlighted: true,
|
|
32
|
+
cta_text: campaign.content.subheader,
|
|
33
|
+
action_text: campaign.cta.header,
|
|
34
|
+
extra_info: {
|
|
35
|
+
category: 'SVOD'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/lib/constants.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export const playPilotBaseUrl = 'https://www.playpilot.com'
|
|
2
|
-
export const apiBaseUrl = 'https://partner-api.playpilot.tech/1.0.0'
|
|
2
|
+
export const apiBaseUrl = 'https://partner-api-staging.playpilot.tech/1.0.0'
|
|
3
|
+
export const imageBaseUrl = 'https://img-staging.playpilot.tech'
|
|
3
4
|
|
|
4
5
|
export const imagePlaceholderDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAB+CAMAAACNgsajAAAAb1BMVEU1Q2fI1N5YZoNVYoFndI9qd5JBT3FFU3S8yNS3xNC4xNFBTnDG0t2lscJJV3e9ytaptcWToLOOm6/BzdiZprh3hJ1aaIWJlatte5VPXHx7iJ9zgZlfbYk3RWmNmq5jcY1XZIO2wtCjsMB+i6I9S25IprTeAAABqUlEQVRo3u3W2ZKCMBCF4T5ExRmRVXBfZnn/Z5wKiU5pz1AJ7ZXV/x03HxVCB0jTNE3TNE3TNO0l2rbPNxcFdk8334AINTUD5eSaWbPoQs0qw0CVN98BzNNgE4NVv+ZHsJliuNVt7UgotATAafp/5mZiG4waAB0N5k0kUeg0wMykKDfLvRTl5pxyCFFupjQVo9ykiRTlphzl5nNQNu8C9Hv2lylDT0W2NMyUoeXdLC68KUNLuM7O9HskQ0uLLAEUR2aOQjfORE5LzHP2PMehxpl2k6otM8eh2aQGkBlieyRBYbs3y5Rk6IPZn8mT65XJR6LcROGErwaoxqLm4XvkiTVsy1FoYe5n06zcjazp1Wk0umHz3k9BT6+bXjXR6PnRtKpr755PfRjx4WPz7tXW/26gGYnOvOmrM7xtiK4qYtDOrpGZtnR7JFcSi+Z1XZt7k5d4NCZmcrWxqMzkbRgqN+nAULHpx1RiylFvftJwlxjUz2bWdpPB7NnSxZih5RFrD20Vai4izGOgeenPukMSUE6hte5denI7NMyU1xrSNE3TNE3TNE17hX4ADHsS0j0OCOoAAAAASUVORK5CYII='
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Image dimensions to be used to generate images from the supplied image UUIDs.
|
|
2
|
+
// The number given is a multiplier of the base 32 pixels.
|
|
3
|
+
// https://docs.google.com/spreadsheets/d/1Nx73ux1fgGKJfuaUeQRwSXUJdSQonPG5DxjW2zxnyz0
|
|
4
|
+
export const ImageDimensions = {
|
|
5
|
+
TopScrollBackground: 'topscrollBackgroundMobile', // 600x140
|
|
6
|
+
TopScrollContent: '8by1x23',
|
|
7
|
+
} as const
|
|
@@ -6,5 +6,18 @@ export const SplitTest = {
|
|
|
6
6
|
MultipleVariants: {
|
|
7
7
|
key: 'multiple_variants',
|
|
8
8
|
numberOfVariants: 4,
|
|
9
|
-
}
|
|
9
|
+
},
|
|
10
|
+
TopScrollFormat: {
|
|
11
|
+
key: 'top_scroll_format',
|
|
12
|
+
numberOfVariants: 2,
|
|
13
|
+
// Variant 0 is separate bubble
|
|
14
|
+
// Variant 1 is inline bubble
|
|
15
|
+
},
|
|
16
|
+
DisplayAdPosition: {
|
|
17
|
+
key: 'display_ad_position',
|
|
18
|
+
numberOfVariants: 3,
|
|
19
|
+
// Variant 0 is display ad in playlinks
|
|
20
|
+
// Variant 1 is display ad above card with highlighted playlink
|
|
21
|
+
// Variant 2 is display ad above card without highlighted playlink
|
|
22
|
+
},
|
|
10
23
|
} as const
|
|
@@ -26,6 +26,9 @@ export const TrackingEvent = Object.freeze({
|
|
|
26
26
|
EditorError: 'ali_editor_error',
|
|
27
27
|
InjectionError: 'ali_injection_error',
|
|
28
28
|
|
|
29
|
+
TopScrollClick: 'ali_top_scroll_click',
|
|
30
|
+
DisplayAdClick: 'ali_display_ad_click',
|
|
31
|
+
|
|
29
32
|
SplitTestView: 'ali_split_test_view',
|
|
30
33
|
SplitTestAction: 'ali_split_test_action'
|
|
31
34
|
})
|
package/src/lib/image.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { imageBaseUrl } from "./constants"
|
|
2
|
+
import type { ImageDimensions } from "./enums/ImageDimensions"
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* NOTE: This is a temporary measure. Images url from the API use a previous format which is to be replaced,
|
|
3
6
|
* but that isn't live yet and requires some extra work. In the meantime we remove part of the URL ourselves.
|
|
@@ -6,3 +9,12 @@ export function removeImageUrlPrefix(url: string | null): string | null {
|
|
|
6
9
|
if (!url) return null
|
|
7
10
|
return url.replace('/src/img', '')
|
|
8
11
|
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a CDN image URL from a UUID.
|
|
15
|
+
*/
|
|
16
|
+
export function imageFromUUID(uuid: string | null, dimensions: (typeof ImageDimensions)[keyof typeof ImageDimensions] | null = null): string {
|
|
17
|
+
if (!uuid?.length) return ''
|
|
18
|
+
|
|
19
|
+
return `${imageBaseUrl}/${uuid}?${dimensions ? `class=${dimensions}&` : ''}optimizer=image`
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type Campaign = {
|
|
2
|
+
campaign_format: CampaignFormat
|
|
3
|
+
campaign_type: 'playlist' | 'video' | 'image'
|
|
4
|
+
campaign_platforms: CampaignPlatform[]
|
|
5
|
+
campaign_name: string
|
|
6
|
+
campaign_start: string
|
|
7
|
+
campaign_end: string
|
|
8
|
+
campaign_region: string
|
|
9
|
+
content: CampaignContent
|
|
10
|
+
cta: CampaignCTA
|
|
11
|
+
content_playlist: object
|
|
12
|
+
provider: object | null
|
|
13
|
+
impression_trackers: string[]
|
|
14
|
+
target_title_uuid: string
|
|
15
|
+
target_title_sid: string
|
|
16
|
+
backfill_providers: string[]
|
|
17
|
+
autogenerated: boolean
|
|
18
|
+
enabled: boolean
|
|
19
|
+
hide_imdb_score: boolean
|
|
20
|
+
hide_sponsored_message: boolean
|
|
21
|
+
disclaimer: string | null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type CampaignContent = {
|
|
25
|
+
header: string | null
|
|
26
|
+
header_logo: string | null
|
|
27
|
+
header_logo_uuid: string | null
|
|
28
|
+
subheader: string | null
|
|
29
|
+
image: string | null
|
|
30
|
+
image_uuid: string | null
|
|
31
|
+
video: string | null
|
|
32
|
+
format: string | null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type CampaignCTA = {
|
|
36
|
+
header: string | null
|
|
37
|
+
subheader: string | null
|
|
38
|
+
image: string | null
|
|
39
|
+
image_uuid: string | null
|
|
40
|
+
url: string | null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type CampaignPlatform = 'web' | 'android_app' | 'ios_app'
|
|
44
|
+
|
|
45
|
+
export type CampaignFormat = 'takeover' | 'horizontal' | 'hero' | 'top_scroll' | 'card'
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Campaign } from "./campaign"
|
|
1
2
|
import type { LinkInjection } from "./injection"
|
|
2
3
|
|
|
3
4
|
export type ScriptConfig = {
|
|
@@ -13,4 +14,5 @@ export type ScriptConfig = {
|
|
|
13
14
|
tracked_events?: { event: string, payload: Record<string, any> }[]
|
|
14
15
|
split_test_identifiers?: Record<string, number>
|
|
15
16
|
evaluated_link_injections?: LinkInjection[]
|
|
17
|
+
ads?: Campaign[]
|
|
16
18
|
}
|
package/src/main.ts
CHANGED
|
@@ -16,6 +16,7 @@ window.PlayPilotLinkInjections = {
|
|
|
16
16
|
tracked_events: [],
|
|
17
17
|
split_test_identifiers: {},
|
|
18
18
|
evaluated_link_injections: [],
|
|
19
|
+
ads: [],
|
|
19
20
|
app: null,
|
|
20
21
|
|
|
21
22
|
initialize(config = { token: '', selector: '', after_article_selector: '', after_article_insert_position: '', language: null, organization_sid: null, domain_sid: null, editorial_token: '' }): void {
|
package/src/routes/+page.svelte
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import EditorTrigger from './components/Editorial/EditorTrigger.svelte'
|
|
15
15
|
import Alert from './components/Editorial/Alert.svelte'
|
|
16
16
|
import TrackingPixels from './components/TrackingPixels.svelte'
|
|
17
|
+
import { fetchAds } from '$lib/ads'
|
|
17
18
|
|
|
18
19
|
let parentElement: HTMLElement | null = $state(null)
|
|
19
20
|
let elements: HTMLElement[] = $state([])
|
|
@@ -43,6 +44,8 @@
|
|
|
43
44
|
await initialize()
|
|
44
45
|
track(TrackingEvent.ArticlePageView)
|
|
45
46
|
|
|
47
|
+
if (aiInjections.length || manualInjections.length) window.PlayPilotLinkInjections.ads = await fetchAds()
|
|
48
|
+
|
|
46
49
|
trackSplitTestView(SplitTest.MultipleVariants)
|
|
47
50
|
})()
|
|
48
51
|
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { SplitTest } from '$lib/enums/SplitTest'
|
|
3
|
+
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
4
|
+
import { trackSplitTestAction, trackSplitTestView } from '$lib/splitTest'
|
|
5
|
+
import { track } from '$lib/tracking'
|
|
6
|
+
import type { Campaign } from '$lib/types/campaign'
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
campaign: Campaign
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { campaign }: Props = $props()
|
|
13
|
+
|
|
14
|
+
const { disclaimer, content, cta } = $derived(campaign)
|
|
15
|
+
const { header, subheader, header_logo: logo, image } = $derived(content)
|
|
16
|
+
const { header: buttonLabel, url: href } = $derived(cta)
|
|
17
|
+
|
|
18
|
+
trackSplitTestView(SplitTest.DisplayAdPosition)
|
|
19
|
+
|
|
20
|
+
function onclick(): void {
|
|
21
|
+
track(TrackingEvent.DisplayAdClick, null, { campaign_name: campaign.campaign_name })
|
|
22
|
+
trackSplitTestAction(SplitTest.DisplayAdPosition, 'click')
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<a {href} target="_blank" class="display" rel="sponsored" {onclick}>
|
|
27
|
+
{#if disclaimer}
|
|
28
|
+
<div class="disclaimer">
|
|
29
|
+
{disclaimer}
|
|
30
|
+
</div>
|
|
31
|
+
{/if}
|
|
32
|
+
|
|
33
|
+
{#if logo || header || subheader || buttonLabel}
|
|
34
|
+
<div class="cta">
|
|
35
|
+
{#if logo}
|
|
36
|
+
<img class="logo" src={logo} alt="" height="40" width="40" />
|
|
37
|
+
{/if}
|
|
38
|
+
|
|
39
|
+
<div>
|
|
40
|
+
{#if header}
|
|
41
|
+
<span class="name">{header}</span>
|
|
42
|
+
{/if}
|
|
43
|
+
|
|
44
|
+
{#if subheader}
|
|
45
|
+
<div class="subheader">{subheader}</div>
|
|
46
|
+
{/if}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{#if buttonLabel}
|
|
50
|
+
<div class="action">{buttonLabel}</div>
|
|
51
|
+
{/if}
|
|
52
|
+
</div>
|
|
53
|
+
{/if}
|
|
54
|
+
|
|
55
|
+
{#if image}
|
|
56
|
+
<img class="background" src={image} alt="" />
|
|
57
|
+
{/if}
|
|
58
|
+
</a>
|
|
59
|
+
|
|
60
|
+
<style lang="scss">
|
|
61
|
+
.display {
|
|
62
|
+
display: block;
|
|
63
|
+
position: relative;
|
|
64
|
+
border-radius: var(--playpilot-display-ad-border-radius, margin(0.5));
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
background: black;
|
|
67
|
+
aspect-ratio: 16 / 9;
|
|
68
|
+
color: white !important;
|
|
69
|
+
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.35);
|
|
70
|
+
font-family: var(--playpilot-detail-font-family, var(--playpilot-font-family));
|
|
71
|
+
line-height: 1.2;
|
|
72
|
+
font-style: normal !important;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.disclaimer {
|
|
76
|
+
position: absolute;
|
|
77
|
+
top: 0;
|
|
78
|
+
left: 0;
|
|
79
|
+
padding: margin(0.5);
|
|
80
|
+
font-size: margin(0.75);
|
|
81
|
+
text-decoration: underline;
|
|
82
|
+
|
|
83
|
+
@media (min-width: 600px) {
|
|
84
|
+
padding: margin(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.cta {
|
|
89
|
+
z-index: 1;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: margin(0.5);
|
|
93
|
+
position: absolute;
|
|
94
|
+
right: 0;
|
|
95
|
+
bottom: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
padding: margin(0.5);
|
|
98
|
+
background: linear-gradient(to right, rgba(110, 110, 110, 1), rgba(85, 85, 85, 0.3));
|
|
99
|
+
font-size: margin(0.875);
|
|
100
|
+
text-decoration: none;
|
|
101
|
+
|
|
102
|
+
@media (min-width: 600px) {
|
|
103
|
+
padding: margin(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.logo {
|
|
108
|
+
border-radius: var(--playpilot-display-ad-border-radius, margin(0.5));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.name {
|
|
112
|
+
font-weight: 500;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.subheader {
|
|
116
|
+
font-size: margin(0.75);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.action {
|
|
120
|
+
margin-left: auto;
|
|
121
|
+
padding: margin(0.5) margin(0.75);
|
|
122
|
+
background: var(--playpilot-display-ad-action-background, white);
|
|
123
|
+
border-radius: var(--playpilot-display-action-border-radius, margin(2));
|
|
124
|
+
transition: transform 50ms;
|
|
125
|
+
text-shadow: none;
|
|
126
|
+
font-weight: var(--playpilot-display-action-font-weight, 500);
|
|
127
|
+
color: var(--playpilot-display-action-text-color, black);
|
|
128
|
+
white-space: nowrap;
|
|
129
|
+
|
|
130
|
+
&:hover {
|
|
131
|
+
transform: scale(1.05);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.background {
|
|
136
|
+
display: block;
|
|
137
|
+
width: 100%;
|
|
138
|
+
height: auto;
|
|
139
|
+
}
|
|
140
|
+
</style>
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ImageDimensions } from '$lib/enums/ImageDimensions'
|
|
3
|
+
import { SplitTest } from '$lib/enums/SplitTest'
|
|
4
|
+
import { TrackingEvent } from '$lib/enums/TrackingEvent'
|
|
5
|
+
import { imageFromUUID } from '$lib/image'
|
|
6
|
+
import { isInSplitTestVariant, trackSplitTestView } from '$lib/splitTest'
|
|
7
|
+
import { track } from '$lib/tracking'
|
|
8
|
+
import type { Campaign } from '$lib/types/campaign'
|
|
9
|
+
import { fade } from 'svelte/transition'
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
campaign: Campaign
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { campaign }: Props = $props()
|
|
16
|
+
|
|
17
|
+
trackSplitTestView(SplitTest.TopScrollFormat)
|
|
18
|
+
|
|
19
|
+
const { disclaimer, content, cta } = $derived(campaign)
|
|
20
|
+
const { format, header, header_logo: logo, image_uuid: backgroundImageUUID } = $derived(content)
|
|
21
|
+
const { header: buttonLabel, url: href } = $derived(cta)
|
|
22
|
+
|
|
23
|
+
const inline = isInSplitTestVariant(SplitTest.TopScrollFormat, 1)
|
|
24
|
+
const simple = $derived(format === 'large')
|
|
25
|
+
|
|
26
|
+
const backgroundImage = $derived(imageFromUUID(backgroundImageUUID, ImageDimensions.TopScrollBackground))
|
|
27
|
+
const contentImage = $derived(imageFromUUID(backgroundImageUUID, ImageDimensions.TopScrollContent))
|
|
28
|
+
|
|
29
|
+
let clientWidth = $state(0)
|
|
30
|
+
let tooltipVisible = $state(false)
|
|
31
|
+
|
|
32
|
+
function trackClick(): void {
|
|
33
|
+
track(TrackingEvent.TopScrollClick, null, { campaign_name: campaign.campaign_name })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function toggleTooltip(event: MouseEvent): void {
|
|
37
|
+
event.preventDefault()
|
|
38
|
+
event.stopPropagation()
|
|
39
|
+
|
|
40
|
+
tooltipVisible = !tooltipVisible
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<a
|
|
45
|
+
{href}
|
|
46
|
+
target="_blank"
|
|
47
|
+
class="top-scroll"
|
|
48
|
+
class:simple
|
|
49
|
+
class:inline
|
|
50
|
+
tabindex="-1"
|
|
51
|
+
onclick={trackClick}
|
|
52
|
+
rel="sponsored"
|
|
53
|
+
style:--width="{clientWidth}px"
|
|
54
|
+
bind:clientWidth>
|
|
55
|
+
<div class="content">
|
|
56
|
+
{#if simple}
|
|
57
|
+
<img class="content-image" src={contentImage} alt={header} width="728" height="90" />
|
|
58
|
+
{:else}
|
|
59
|
+
{#if logo}
|
|
60
|
+
<img class="logo" src={logo} alt="" width="50" height="50" />
|
|
61
|
+
{/if}
|
|
62
|
+
|
|
63
|
+
<p class="tagline">{header}</p>
|
|
64
|
+
|
|
65
|
+
{#if buttonLabel}
|
|
66
|
+
<button class="button">{buttonLabel}</button>
|
|
67
|
+
{/if}
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{#if !simple}
|
|
72
|
+
{#if backgroundImageUUID}
|
|
73
|
+
<div class="background" style:--background="url('{backgroundImage}')"></div>
|
|
74
|
+
{/if}
|
|
75
|
+
|
|
76
|
+
{#if disclaimer}
|
|
77
|
+
<button class="tooltip" onclick={toggleTooltip}>
|
|
78
|
+
<div class="disclaimer">i</div>
|
|
79
|
+
|
|
80
|
+
{#if tooltipVisible}
|
|
81
|
+
<div class="tooltip-content" transition:fade={{ duration: 50 }}>
|
|
82
|
+
{disclaimer}
|
|
83
|
+
</div>
|
|
84
|
+
{/if}
|
|
85
|
+
</button>
|
|
86
|
+
{/if}
|
|
87
|
+
{/if}
|
|
88
|
+
</a>
|
|
89
|
+
|
|
90
|
+
<style lang="scss">
|
|
91
|
+
$border-radius-size: var(--playpilot-top-scroll-border-radius, var(--playpilot-popover-border-radius, margin(1)));
|
|
92
|
+
|
|
93
|
+
.top-scroll {
|
|
94
|
+
position: relative;
|
|
95
|
+
display: block;
|
|
96
|
+
width: 100%;
|
|
97
|
+
border-radius: $border-radius-size;
|
|
98
|
+
background: black;
|
|
99
|
+
color: var(--playpilot-top-scroll-text-color, white);
|
|
100
|
+
font-family: var(--playpilot-top-scroll-font-family, var(--playpilot-detail-font-family, var(--playpilot-font-family)));
|
|
101
|
+
font-size: var(--playpilot-top-scroll-font-size, var(--playpilot-detail-font-size, 14px));
|
|
102
|
+
text-decoration: none;
|
|
103
|
+
line-height: 1.35;
|
|
104
|
+
|
|
105
|
+
&.inline {
|
|
106
|
+
border-radius: $border-radius-size $border-radius-size 0 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.content {
|
|
111
|
+
display: flex;
|
|
112
|
+
z-index: 1;
|
|
113
|
+
position: relative;
|
|
114
|
+
align-items: center;
|
|
115
|
+
height: 100%;
|
|
116
|
+
min-height: margin(4.5);
|
|
117
|
+
padding: margin(0.25) margin(0.5);
|
|
118
|
+
gap: margin(0.5);
|
|
119
|
+
color: var(--playpilot-top-scroll-text-color, white);
|
|
120
|
+
|
|
121
|
+
.simple & {
|
|
122
|
+
justify-content: center;
|
|
123
|
+
min-height: 0;
|
|
124
|
+
padding: 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.logo {
|
|
129
|
+
border-radius: var(--playpilot-top-scroll-logo-border-radius, margin(0.5));
|
|
130
|
+
background: black;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.tagline {
|
|
134
|
+
margin: 0;
|
|
135
|
+
text-shadow: var(--playpilot-shadow);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.button {
|
|
139
|
+
margin-left: auto;
|
|
140
|
+
margin-right: margin(1);
|
|
141
|
+
padding: margin(0.25) margin(0.5);
|
|
142
|
+
background: var(--playpilot-top-scroll-button-background, white);
|
|
143
|
+
border: 0;
|
|
144
|
+
border-radius: var(--playpilot-top-scroll-button-border-radius, margin(0.25));
|
|
145
|
+
box-shadow: var(--playpilot-shadow);
|
|
146
|
+
color: var(--playpilot-top-scroll-button-text-color, black);
|
|
147
|
+
font-family: inherit;
|
|
148
|
+
font-size: inherit;
|
|
149
|
+
line-height: inherit;
|
|
150
|
+
|
|
151
|
+
&:hover {
|
|
152
|
+
outline: margin(0.25) solid var(--playpilot-top-scroll-button-background, rgba(white, 0.35));
|
|
153
|
+
background: var(--playpilot-top-scroll-button-background, white);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
&:active {
|
|
157
|
+
background: var(--playpilot-top-scroll-button-background, white);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.background {
|
|
162
|
+
z-index: 0;
|
|
163
|
+
position: absolute;
|
|
164
|
+
top: 0;
|
|
165
|
+
right: 0;
|
|
166
|
+
bottom: 0;
|
|
167
|
+
left: 0;
|
|
168
|
+
border-radius: $border-radius-size;
|
|
169
|
+
background-image: var(--background);
|
|
170
|
+
background-position: center;
|
|
171
|
+
background-size: cover;
|
|
172
|
+
opacity: 0.4;
|
|
173
|
+
|
|
174
|
+
.top-scroll:hover & {
|
|
175
|
+
filter: brightness(1.15);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.inline & {
|
|
179
|
+
border-radius: $border-radius-size $border-radius-size 0 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.content-image {
|
|
184
|
+
display: block;
|
|
185
|
+
max-width: 100%;
|
|
186
|
+
height: auto;
|
|
187
|
+
background: black;
|
|
188
|
+
border-radius: var(--playpilot-top-scroll-border-radius, var(--playpilot-popover-border-radius, margin(1)));
|
|
189
|
+
|
|
190
|
+
.top-scroll:hover & {
|
|
191
|
+
filter: brightness(1.15);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.disclaimer {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
199
|
+
border: var(--playpilot-top-scroll-disclaimer-border, 2px solid rgba(255, 255, 255, 0.5));
|
|
200
|
+
padding: margin(0.25);
|
|
201
|
+
height: margin(1.25);
|
|
202
|
+
width: margin(1.25);
|
|
203
|
+
border-radius: 99px;
|
|
204
|
+
color: var(--playpilot-top-scroll-disclaimer-text-color, rgba(255, 255, 255, 0.75));
|
|
205
|
+
font-weight: bold;
|
|
206
|
+
line-height: 1;
|
|
207
|
+
|
|
208
|
+
&:hover {
|
|
209
|
+
border-color: var(--playpilot-top-scroll-disclaimer-hover-border-color, white);
|
|
210
|
+
color: var(--playpilot-top-scroll-disclaimer-hover-text-color, white);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.tooltip {
|
|
215
|
+
z-index: 2;
|
|
216
|
+
position: absolute;
|
|
217
|
+
right: 0;
|
|
218
|
+
bottom: 0;
|
|
219
|
+
padding: margin(0.25);
|
|
220
|
+
background: transparent;
|
|
221
|
+
border: 0;
|
|
222
|
+
color: var(--playpilot-top-scroll-text-color, white);
|
|
223
|
+
cursor: pointer;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.tooltip-content {
|
|
227
|
+
display: block;
|
|
228
|
+
z-index: 20;
|
|
229
|
+
position: absolute;
|
|
230
|
+
right: 100%;
|
|
231
|
+
bottom: margin(0.25);
|
|
232
|
+
width: calc(var(--width) * 0.8);
|
|
233
|
+
padding: margin(0.5);
|
|
234
|
+
border-radius: margin(1);
|
|
235
|
+
background: var(--playpilot-content);
|
|
236
|
+
box-shadow: var(--playpilot-shadow);
|
|
237
|
+
line-height: 1.1;
|
|
238
|
+
text-align: right;
|
|
239
|
+
}
|
|
240
|
+
</style>
|