diff --git a/README.md b/README.md index 90d2b39..939b973 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ Visit the [interactive playground](https://playcode.io/capture_eye_demo) for the | `nid` | Yes | The unique [Nid](https://docs.numbersprotocol.io/introduction/numbers-protocol/defining-web3-assets/numbers-id-nid) of the asset.
`` | | `layout` | No | Decides which layout to display. Default value is `original`. Additional option includes `curated`.
`` | | `visibility` | No | Visibility behavior. Default value is `hover`, showing Eye on mouse hover. Setting it to option `always` will make the Eye always shown. This attribute is `always` and cannot be customized on mobile devices.
`` | -| `color` | No | The widget color. Default value is #377dde (blue), and for mobile, the default value is #333333 (gray).
`` | +| `position` | No | The widget position. Default value is `top left`. Additional option includes `top right`, `bottom left`, and `bottom right`.
`` | +| `color` | No | The widget color. Default value is `#377dde` (blue), and for mobile, the default value is `#333333` (gray).
`` | | `cz-title` | No | Override the copyright zone title.
`` | | `eng-img` | No | Sets the image for the engagement zone banner. Recommended dimensions: `320x120 px`. Supports multiple `eng-img` and `eng-link` pairs for rotating banners. If multiple pairs are provided by using comma to seperate each URL entry, the banner will rotate every 5 seconds. Ensure that the number of `eng-img` matches the number of `eng-link` entries. Use URL encoding to replace commas with `%2C` in the URLs.
`` | | `eng-link` | No | Sets the URL for the engagement zone banner link. Each `eng-link` should correspond to an `eng-img` for proper pairing in rotating banners, following the same comma-separated rule.
`` | diff --git a/dev/index.html b/dev/index.html index ef8a983..7f448dc 100644 --- a/dev/index.html +++ b/dev/index.html @@ -66,6 +66,7 @@ eng-link="https://captureapp.xyz, https://defiance.media/" action-button-text="View docs" action-button-link="https://docs.captureapp.xyz" + position="bottom right" > ${this.generateCaptureEyeSvg(color, size)} @@ -157,6 +167,7 @@ export class CaptureEye extends LitElement { position: { top: buttonRect.top + window.scrollY, left: buttonRect.left + window.scrollX, + name: this.position, }, }; modalManager.updateModal(modalOptions); @@ -172,12 +183,17 @@ export class CaptureEye extends LitElement { } private generateCaptureEyeSvg( - color: string, size: number + color: string, + size: number ): HTMLTemplateResult { return html` - + diff --git a/src/constant.ts b/src/constant.ts index 2786de4..95124cb 100644 --- a/src/constant.ts +++ b/src/constant.ts @@ -29,6 +29,7 @@ interface ConstantType { layout: Layout; visibility: Visibility; color: Color; + position: Position; } interface Layout { @@ -46,6 +47,13 @@ interface Color { mobileEye: string; } +interface Position { + topLeft: string; + topRight: string; + bottomLeft: string; + bottomRight: string; +} + const numbersCdnUrl = 'https://static-cdn.numbersprotocol.io'; export const Constant: ConstantType = { @@ -83,5 +91,11 @@ export const Constant: ConstantType = { color: { defaultEye: '#377dde', mobileEye: '#333333', - } + }, + position: { + topLeft: 'top left', + topRight: 'top right', + bottomLeft: 'bottom left', + bottomRight: 'bottom right', + }, }; diff --git a/src/media-viewer/media-viewer-styles.ts b/src/media-viewer/media-viewer-styles.ts index e50ff48..6128cee 100644 --- a/src/media-viewer/media-viewer-styles.ts +++ b/src/media-viewer/media-viewer-styles.ts @@ -9,6 +9,7 @@ export function getMediaViewerStyles() { video { width: var(--media-viewer-width, 100%); height: var(--media-viewer-height, auto); + vertical-align: bottom; } .unsupported { color: red; diff --git a/src/modal/modal-styles.ts b/src/modal/modal-styles.ts index 17e8c5d..c17b9f8 100644 --- a/src/modal/modal-styles.ts +++ b/src/modal/modal-styles.ts @@ -32,7 +32,6 @@ export function getModalStyles() { align-items: flex-start; opacity: 0; transform: scale(0.5); - transform-origin: top left; transition: opacity 0.3s ease-in-out, transform 0.3s ease-in; position: absolute; } @@ -60,14 +59,10 @@ export function getModalStyles() { .close-button { position: absolute; - top: -16px; - left: -16px; display: flex; justify-content: center; align-items: center; z-index: 10001; - width: 32px; - height: 32px; cursor: pointer; border-radius: 100vw; opacity: 0; @@ -75,13 +70,6 @@ export function getModalStyles() { transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; } - .close-button.mobile { - top: -12px; - left: -12px; - width: 24px; - height: 24px; - } - .close-button-visible { opacity: 1; transform: scale(1) rotate(90deg); diff --git a/src/modal/modal.ts b/src/modal/modal.ts index 0ca66f3..6dacd1e 100644 --- a/src/modal/modal.ts +++ b/src/modal/modal.ts @@ -16,12 +16,17 @@ export function formatTxHash(txHash: string): string { } export function generateCaptureEyeCloseSvg( - color: string, size: number + color: string, + size: number ): HTMLTemplateResult { return html` - ${generateCaptureEyeCloseSvg(Constant.color.defaultEye, 32).strings.join()} + ${generateCaptureEyeCloseSvg( + Constant.color.defaultEye, + 32 + ).strings.join()} @@ -216,19 +223,48 @@ suite('capture-eye-modal', () => { `); - const position = { top: 100, left: 200 }; + const position = { top: 100, left: 200, name: '' }; el.updateModalOptions({ nid: '123', position, }); + el.modalHidden = false; await el.updateComplete; - const modal = el.shadowRoot?.querySelector('.modal') as HTMLDivElement; + let modal = el.shadowRoot?.querySelector('.modal') as HTMLDivElement; expect(modal.style.top).to.equal('116px'); // Assuming 1rem = 16px (this may vary) expect(modal.style.left).to.equal('216px'); + + // Position is bottom right with enough space in that direction + el.modalHidden = true; + el.modalHidden = false; + el.updateModalOptions({ + nid: '123', + position: { top: 600, left: 800, name: 'bottom right' }, + }); + await el.updateComplete; + + modal = el.shadowRoot?.querySelector('.modal') as HTMLDivElement; + + expect(modal.style.top).to.equal(`${600 + 16 - modal.offsetHeight}px`); + expect(modal.style.left).to.equal(`${800 + 16 - modal.offsetWidth}px`); + + // Position is bottom right without enough space in that direction + el.modalHidden = true; + el.modalHidden = false; + el.updateModalOptions({ + nid: '123', + position: { top: 100, left: 200, name: 'bottom right' }, + }); + await el.updateComplete; + + modal = el.shadowRoot?.querySelector('.modal') as HTMLDivElement; + + expect(modal.style.top).to.equal('116px'); + expect(modal.style.left).to.equal('216px'); }); test('clears modal options correctly', async () => { @@ -247,6 +283,7 @@ suite('capture-eye-modal', () => { link: 'https://example.com', }, ], + position: { top: 100, left: 200, name: '' }, }); await el.updateComplete; @@ -259,6 +296,7 @@ suite('capture-eye-modal', () => { expect(el.nid).to.equal(''); expect(el.layout).to.equal(Constant.layout.original); expect((el as any)._engagementZones).to.deep.equal([]); + expect((el as any)._position).to.equal(undefined); }); test('modal visibility toggle works with transition end', async () => {