Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,66 @@ use `topsort-banner-slot` as children elements.
| location | Optional String | The location for geotargeting |
| new-tab | Optional Boolean | Opens the banner's link in a new tab (defaults to false) |
| context | Optional Boolean | Uses the element as a context provider to render multiple banners |
| class | Optional String | Custom CSS class to apply to the banner container |

\* Only one of `[category-id, category-ids, category-disjunctions]` must be set.
If multiple are set, only the first will be considered, in that order.

# Styling

The banner component is designed to integrate seamlessly with your existing CSS system.
Each banner is rendered inside a container div with the class `ts-banner`,
making it easy to target with CSS selectors.

## CSS Targeting

You can style banners using standard CSS selectors:

```css
/* Target all banner containers */
.ts-banner {
padding: 10px;
margin: 10px;
border: 1px solid #ccc;
}

/* Target banners with specific dimensions */
.ts-banner[data-ts-width="800"] {
max-width: 800px;
}
```

## Custom CSS Classes

You can pass custom CSS classes to the banner component using the `class` attribute:

```html
<topsort-banner width="600" height="400" id="my-slot" class="my-custom-banner"></topsort-banner>
```

The custom class will be applied alongside the `ts-banner` class, allowing you to
integrate the banner into your existing CSS system.

## Retrieving Width and Height

The width and height values are easily accessible via:

- **Data attributes**: `data-ts-width` and `data-ts-height` on the container element
- **CSS custom properties**: `--ts-banner-width` and `--ts-banner-height` on the container element

```css
/* Use data attributes in CSS */
.ts-banner[data-ts-width] {
/* Styles for banners with width set */
}

/* Use CSS custom properties */
.ts-banner {
width: var(--ts-banner-width, 100%);
height: var(--ts-banner-height, auto);
}
```

# Banner Slot Attributes
| Name | Type | Description |
|------|--------|-----------------------------------------------------------------------------------------------------------------------|
Expand Down
11 changes: 9 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
justify-content: center;
padding: 20px;
}
.ts-banner {
padding: 10px;
margin: 10px;
}
.ts-banner[data-ts-width="800"] {
border: 1px solid #ddd;
}
</style>
<body>
<div style="padding-right: 1rem">
Expand All @@ -52,11 +59,11 @@ <h3>Standalone Banner</h3>
&lt;topsort-banner id="an-example-slot" width="800" height="400"&gt;&lt;/topsort-banner&gt;
</code>
</pre>
<div style="outline 1px solid black">
<div style="outline: 1px solid black">
<topsort-banner id="an-example-slot" width="800" height="400"></topsort-banner>
</div>
</div>
<div style="outline 1px solid black">
<div style="outline: 1px solid black">
<h3>Multiple Banners under one context</h3>
<pre>
<code>
Expand Down
55 changes: 40 additions & 15 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ function getNoWinnersElement(): TemplateResult {

function getBannerElement(
banner: Banner,
width: number,
height: number,
newTab: boolean,
width?: number,
height?: number,
bannerClass?: string,
): TemplateResult {
Comment on lines +77 to 80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't change the order of variables, thats a breaking change

if (window.TS_BANNERS.getBannerElement) {
const element = window.TS_BANNERS.getBannerElement(banner);
Expand All @@ -102,19 +103,39 @@ function getBannerElement(
return false;
}
})();

const containerClass = bannerClass ? `ts-banner ${bannerClass}` : "ts-banner";

const containerStyle = [
"display: block",
width ? `--ts-banner-width: ${width}px` : "",
height ? `--ts-banner-height: ${height}px` : "",
]
.filter(Boolean)
.join("; ");

// let CSS cascade
const mediaStyle =
width && height
? `width: ${width}px; height: ${height}px; object-fit: cover;`
: width
? `width: ${width}px; height: auto; object-fit: cover;`
: height
? `width: 100%; height: ${height}px; object-fit: cover;`
: "width: 100%; height: auto; object-fit: cover;";

const media = isVideo
? html`
<hls-video
src="${src}"
width="${width}px"
height="${height}px"
styles=${mediaStyle}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im generally ok with this if there are no users of banners.js using video; it is the right move. the otehr option is to do a major bump due to your previous change

></hls-video>
`
: html`
<img
src="${src}"
alt="Topsort banner"
style="width:${width}px; height:${height}px; object-fit:cover;"
style=${mediaStyle}
/>
`;

Expand All @@ -124,9 +145,12 @@ function getBannerElement(
: html`<a href="${href}">${media}</a>`;
return html`
<div
class=${containerClass}
data-ts-clickable
data-ts-resolved-bid=${banner.resolvedBidId}
class="ts-banner"
data-ts-width=${width ?? ""}
data-ts-height=${height ?? ""}
style=${containerStyle}
>
${wrappedMedia}
</div>
Expand All @@ -145,6 +169,7 @@ const bannerContextHasChanged = (newVal: BannerContext, oldVal?: BannerContext)
newVal.width !== oldVal.width ||
newVal.height !== oldVal.height ||
newVal.newTab !== oldVal.newTab ||
newVal.bannerClass !== oldVal.bannerClass ||
!!newVal.error !== !!oldVal.error ||
newVal.banners?.length !== oldVal.banners?.length
);
Expand Down Expand Up @@ -181,6 +206,7 @@ export class TopsortBanner extends BannerComponent(LitElement) {
width: this.width,
height: this.height,
newTab: this.newTab,
bannerClass: this.bannerClass,
};

@property({ type: Boolean, attribute: "context" })
Expand All @@ -203,7 +229,7 @@ export class TopsortBanner extends BannerComponent(LitElement) {
if (!banners.length) {
return getNoWinnersElement();
}
return getBannerElement(banners[0], this.width, this.height, this.newTab);
return getBannerElement(banners[0], this.newTab, this.width, this.height, this.bannerClass);
},
error: (error) => getErrorElement(error),
});
Expand All @@ -221,13 +247,15 @@ export class TopsortBanner extends BannerComponent(LitElement) {
if (
changedProperties.has("width") ||
changedProperties.has("height") ||
changedProperties.has("newTab")
changedProperties.has("newTab") ||
changedProperties.has("bannerClass")
) {
Promise.resolve().then(() => {
this.context = {
width: this.width,
height: this.height,
newTab: this.newTab,
bannerClass: this.bannerClass,
};
});
}
Expand Down Expand Up @@ -263,9 +291,10 @@ export class TopsortBannerSlot extends LitElement {
}
return getBannerElement(
this.context.banners[this.rank - 1],
this.context.newTab,
this.context.width,
this.context.height,
this.context.newTab,
this.context.bannerClass,
);
}

Expand All @@ -278,8 +307,7 @@ export class TopsortBannerSlot extends LitElement {
@customElement("hls-video")
export class HlsVideo extends LitElement {
@property({ type: String }) src = ""; // HLS manifest URL
@property({ type: String }) width = "800px";
@property({ type: String }) height = "400px";
@property({ type: String }) styles = "";

private get videoId() {
try {
Expand All @@ -297,6 +325,7 @@ export class HlsVideo extends LitElement {
autoplay
loop
playsinline
style=${this.styles}
></video>
`;
}
Expand All @@ -305,10 +334,6 @@ export class HlsVideo extends LitElement {
const video = this.shadowRoot?.getElementById(this.videoId) as HTMLVideoElement;
if (!video) return;

video.style.width = this.width;
video.style.height = this.height;
video.style.objectFit = "cover";

let Hls: HlsConstructor;
try {
Hls = await hlsDependency.load();
Expand Down
4 changes: 4 additions & 0 deletions src/mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export declare class BannerComponentInterface {
searchQuery?: string;
location?: string;
newTab: boolean;
bannerClass?: string;

emitEvent(status: string): void;
buildAuction(slots: number): Auction;
Expand Down Expand Up @@ -50,6 +51,9 @@ export const BannerComponent = <T extends Constructor<LitElement>>(Base: T) => {
@property({ attribute: "new-tab", type: Boolean })
readonly newTab: boolean = false;

@property({ attribute: "class", type: String })
readonly bannerClass?: string;

buildAuction(slots: number): Auction {
const device = getDeviceType();
const auction: Auction = {
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface BannerContext {
width: number;
height: number;
newTab: boolean;
bannerClass?: string;
banners?: Banner[];
error?: unknown;
}
Expand Down