diff --git a/README.md b/README.md
index 1ac2571..dc40fac 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,24 @@ class MyPagedThing extends LitElement {
customElements.define('my-paged-thing', MyPagedThing);
```
+If you're using Shoelace in your own project and you want to avoid loading two different copies, import like this:
+
+```js
+import '@shoelace-style/shoelace/dist/components/switch/switch.js';
+import '@shoelace-style/shoelace/dist/components/icon/icon.js';
+import '@lalomartins/shoestring-pagination/shoestring-pagination.js';
+```
+
+Otherwise, if you _want_ to use the bundled Shoelace, do this somewhere in your project (just once):
+
+```js
+import {setBasePath} '@lalomartins/shoestring-pagination';
+// …
+setBasePath("node_modules/@lalomartins/shoestring-pagination/node_modules/@shoelace-style/shoelace/dist/");
+```
+
+(You can also use CDNed Shoelace if you prefer.)
+
## API
Attributes:
@@ -83,6 +101,29 @@ npm i @lalomartins/shoestring-pagination
You don't need to import Shoelace on your own code if you're not using it, but you _do_ need to load your own CSS, whether it's from CDN, or from `node_modules`, or copying it into your build. You can check the [Shoelace install instructions](https://shoelace.style/getting-started/installation) for details.
+## CDN
+
+```html
+
+
+
+
+```
+
+If the arrows don't show up, tweak your import order to make sure you have the Shoelace base path set before Pagination loads.
+
## Screenshots
![Light mode](./docs/Screen%20Shot%202023-12-24%20at%2019.34.27.png)
diff --git a/cdn/shoestring-pagination.js b/cdn/shoestring-pagination.js
new file mode 100644
index 0000000..caf0467
--- /dev/null
+++ b/cdn/shoestring-pagination.js
@@ -0,0 +1,204 @@
+/**
+ * @license
+ * Copyright 2032 Lalo Martins
+ * SPDX-License-Identifier: MIT
+ */
+
+import {
+ LitElement,
+ css,
+ html,
+} from 'https://cdn.jsdelivr.net/npm/lit@3.0.0/+esm';
+
+/**
+ * A web component for pagination that uses Shoelace buttons for consistent UI.
+ *
+ * @element shoestring-pagination
+ *
+ * @dependency sl-button
+ * @dependency sl-icon-button
+ * @dependency sl-visually-hidden
+ *
+ * @attr {Number} current - The current page
+ * @attr {Number} total - Total number of items
+ * @attr {Number} [page-size=10] - How many items are in a page
+ * @attr {Number} [surrounding-pages=2] - How many pages to display before and after current at most
+ * @attr {Boolean} hide-on-single-page - If set, and all items fit in one page, hide the element
+ *
+ * @fires page-change - Indicates when the page changes; value is in `event.detail.page`
+ */
+export class Pagination extends LitElement {
+ static properties = {
+ current: {
+ type: Number,
+ },
+ pageSize: {
+ type: Number,
+ attribute: 'page-size',
+ },
+ surroundingPages: {
+ type: Number,
+ attribute: 'surrounding-pages',
+ },
+ total: {
+ type: Number,
+ },
+ hideOnSinglePage: {
+ type: Boolean,
+ attribute: 'hide-on-single-page',
+ },
+ };
+
+ static styles = css`
+ :host {
+ display: block;
+ }
+
+ nav {
+ display: flex;
+ align-items: center;
+ }
+ `;
+
+ constructor() {
+ super();
+ this.current = 1;
+ this.pageSize = 10;
+ this.surroundingPages = 2;
+ this.total = 1;
+ this.hideOnSinglePage = false;
+ }
+
+ generatePages() {
+ const arr = [];
+ for (
+ let i = Math.max(1, this.current - this.surroundingPages);
+ i <= Math.min(this.totalPages, this.current + this.surroundingPages);
+ i++
+ ) {
+ arr.push(i);
+ }
+
+ return arr;
+ }
+
+ _dispatchPrev() {
+ const event = new CustomEvent('page-change', {
+ bubbles: true,
+ composed: true,
+ detail: {page: this.current - 1},
+ });
+
+ this.dispatchEvent(event);
+ }
+
+ _dispatchNext() {
+ const event = new CustomEvent('page-change', {
+ bubbles: true,
+ composed: true,
+ detail: {page: this.current + 1},
+ });
+
+ this.dispatchEvent(event);
+ }
+
+ render() {
+ this.totalPages = Math.ceil(this.total / this.pageSize);
+
+ if (this.hideOnSinglePage && this.totalPages < 2) {
+ return html`
+
+
+
+ `;
+ }
+
+ const pages = this.generatePages();
+ return html`
+
+ `;
+ }
+}
+customElements.define('shoestring-pagination', Pagination);
+export default Pagination;
+
+export class PaginationPageButton extends LitElement {
+ static properties = {page: {type: Number}, current: {type: Boolean}};
+
+ constructor() {
+ super();
+ this.page = 1;
+ this.current = false;
+ }
+
+ _dispatch() {
+ const event = new CustomEvent('page-change', {
+ bubbles: true,
+ composed: true,
+ detail: {page: this.page},
+ });
+
+ this.dispatchEvent(event);
+ }
+
+ render() {
+ return html`
+ ${this.page}
+ `;
+ }
+}
+customElements.define(
+ 'shoestring-pagination-page-button',
+ PaginationPageButton
+);
diff --git a/dev/index.html b/dev/index.html
index 4f371ef..ebf9fd5 100644
--- a/dev/index.html
+++ b/dev/index.html
@@ -16,7 +16,7 @@
/>
@@ -26,6 +26,10 @@
/>
+