Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: banner-context #44

Merged
merged 12 commits into from
Jul 8, 2024
Merged
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_TS_TOKEN=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
.DS_Store
dist/
types/
.env
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ Directly from unpkg.com
</body>
```

## Rendering multiple banners with one slot ID

You can render multiple banners using the same slot ID and dimensions by setting up
a banner context. This is useful when you want to run an auction with multiple results.
To do that you have to pass the attribute `context="true"` to the `topsort-banner` and
use `topsort-banner-slot` as children elements.

```html
<topsort-banner context="true" width="600" height="400" id="<your slot id>">
<topsort-banner-slot rank="1"></topsort-banner-slot>
jbergstroem marked this conversation as resolved.
Show resolved Hide resolved
<topsort-banner-slot rank="2"></topsort-banner-slot>
<topsort-banner-slot rank="3"></topsort-banner-slot>
</topsort-banner-context>
```

# Banner Attributes

| Name | Type | Description |
Expand All @@ -58,11 +73,17 @@ Directly from unpkg.com
| category-disjunctions* | Optional String | Comma (,) separated list of category IDs, the item must match any |
| search-query | Optional String | The search query of the current page |
| location | Optional String | The location for geotargeting |
| new-tab | Optional Boolean | Opens the banner's link in a new tab (defaults to false) |
| 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 |

\* 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.

# Banner Slot Attributes
| Name | Type | Description |
|------|--------|-----------------------------------------------------------------------------------------------------------------------|
| rank | Number | The ranking of the slot. Ranks should be sorted the same as the winning bids. The lower the rank, the higher the bid |

# Banner Behaviors

| Function Name | Arg type | Return Type | Description |
Expand Down
51 changes: 47 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<script>
// Set up authentication for auctions and events
window.TS = {
token: "<your-topsort-token>",
token: "%VITE_TS_TOKEN%",
};

// Setup @topsort/banners.js
Expand All @@ -25,11 +25,14 @@
},
getErrorElement(error) {
const div = document.createElement("div");
const pre = document.createElement("pre");
if (error.name === "TopsortConfigurationError") {
div.innerText = error.message;
pre.innerText = error.message;
} else {
div.innerText = "Couldn't load Banner. Check console for more details.";
pre.innerText = "Couldn't load Banner. Check console for more details.";
pre.innerText = `${error.name}: ${error.message}`;
}
div.appendChild(pre);
return div;
},
};
Expand All @@ -42,8 +45,48 @@
}
</style>
<body>
<div style="padding-right: 1rem">
<h3>Standalone Banner</h3>
<pre>
<code>
&lt;topsort-banner id="an-example-slot" width="800" height="400"&gt;&lt;/topsort-banner&gt;
</code>
</pre>
<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">
<topsort-banner id="<your-slot-id>" width="600" height="400"></topsort-banner>
<h3>Multiple Banners under one context</h3>
<pre>
<code>
&lt;topsort-banner id="an-example-slot" width="800" height="400" context&gt;
&lt;div&gt;
&lt;h3&gt;First Banner&lt;/h3&gt;
&lt;pre&gt;
&lt;code&gt;
&lt;topsort-banner-slot rank="1"&gt;&lt;/topsort-banner-slot&gt;
&lt;/code&gt;
&lt;/pre&gt;
&lt;topsort-banner-slot rank="1"&gt;&lt;/topsort-banner-slot&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;Second Banner&lt;/h3&gt;
&lt;topsort-banner-slot rank="2"&gt;&lt;/topsort-banner-slot&gt;
&lt;/div&gt;
&lt;/topsort-banner&gt;
</code>
</pre>
<topsort-banner id="an-example-slot" width="800" height="400" context="true">
<div>
<h3>First Banner</h3>
<topsort-banner-slot rank="1"></topsort-banner-slot>
</div>
<div>
<h3>Second Banner</h3>
<topsort-banner-slot rank="2"></topsort-banner-slot>
</div>
</topsort-banner>
</div>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"vite-plugin-dts": "^3.8.3"
},
"dependencies": {
"@lit/context": "^1.1.2",
"@lit/task": "^1.0.1",
"lit": "^3.1.3",
"skeleton-webcomponent-loader": "^2.1.4"
Expand Down
10 changes: 10 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions src/auction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { TopsortRequestError } from "./errors";
import type { Auction, Banner } from "./types";

export const getDeviceType = (): "mobile" | "desktop" => {
const ua = navigator.userAgent;
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) {
//return "tablet";
return "mobile";
}
if (
/Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(
ua,
)
) {
return "mobile";
}
return "desktop";
};

interface AuctionOptions {
signal: AbortSignal;
logError: (error: unknown) => void;
}

export async function runAuction(
auction: Auction,
{ signal, logError }: AuctionOptions,
): Promise<Banner[]> {
const device = getDeviceType();
const token = window.TS.token;
const url = window.TS.url || "https://api.topsort.com";
const res = await fetch(new URL(`${url}/v2/auctions`), {
method: "POST",
mode: "cors",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
"X-UA": `topsort/banners-${import.meta.env.PACKAGE_VERSION} (${device})`,
},
body: JSON.stringify({
auctions: [auction],
}),
signal,
});
if (!res.ok) {
const error = await res.json();
logError(error);
throw new Error(error.message);
}
const data = await res.json();
const result = data.results[0];
if (!result) throw new TopsortRequestError("No auction results", res.status);
if (result.error) {
logError(result.error);
throw new Error(result.error);
}
return result.winners;
}
Loading