npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@adalong/widget

v6.0.0

Published

AdAlong widget library

Downloads

425

Readme

AdAlong Widget library

Table of contents

Getting Started

Browser compatibility

This package doesn't support internet explorer.

Installation

Via NPM

Install the plugin with NPM

npm i @adalong/widget

Then you can import it in your code

import AdalongWidget from '@adalong/widget';

Via CDN

Add the CDN url directly in your HTML code to make it available globally. Ensure to replace [VERSION] with the right version.

<script src="https://cdn.jsdelivr.net/npm/@adalong/widget@[VERSION]/dist/adalongWidget.js"></script>

Start

First, you need a tag in which to put the widget. For example:

<div id="widget"></div>

You can define two different types of media sources: collections & products.
Add the data-products attribute to load the media linked to the provided products.
Add the data-collections attribute to load the media linked to the provided collections.
Those values must be an array of strings referring to respectively the product references and the collection ids.

<div id="widget" data-products='["PRODUCT_REF1", "PRODUCT_REF1", ...]' data-collections='["COLLECTION_ID1", "COLLECTION_ID2", ...]'></div>

In case you don't specify any data-* attributes, the media would come from the fallback sources defined in the widget configuration.

Then you can instantiate the widget with your API key and settings and load it by giving the CSS selector of the DOM element.

const adalongWidget = new AdalongWidget('token', { id: 'customUniqId' });

await adalongWidget.load('#widget');

console.log(adalongWidget.layout); // carousel, mosaic or wall

Once instantiated, all widgets in the page can also be retrieved using the global object window.adalongWidgetAPI.

// subscribe on events for all widgets
window.adalongWidgetAPI.widgets.forEach((widget) => widget.onEvent(...))

// find a particular widget from another script in the page
window.adalongWidgetAPI.widgets.find((widget) => widget.id === 'customUniqId')

Events

You can also subscribe to events :

adalongWidget.onEvent('postOpened', (event) => {
  console.log(event.post);
  // console.log(event.product)
  // console.log(event.position)
  // console.log(event.direction)
  // console.log(event.elapsedSeconds)
});

For example, this would be the type of information you could receive from an event about a post :

export interface IMedia {
  id: string;
  type: 'image' | 'video' | 'text';
  caption: string;
  source: 'instagram' | 'twitter';
  username?: string;
  post: string;
  image?: string;
  video?: string;
  thumbnail?: string;
  products?: IProduct[];
  // local properties set by the browser
  postIndex: number;
}

Available events are 'widgetLoaded', 'widgetLoadingFailed', 'thumbnailLoaded', 'thumbnailUnavailable', 'thumbnailHover', 'thumbnailClicked', 'originalPostOpened', 'postOpened', 'postClosed', 'postNavigation', 'videoPlayed', 'carouselArrowClicked', 'carouselNativeScroll', 'shopThisLook', 'minContentNotReached', 'minContentReached', 'widgetViewed'

For more details about events, please refer to the EventMap interface in ./src/types.ts

A custom event is also emitted when a new widget instance is created in the page.

document.addEventListener('adalongWidgetCreated', ({ detail }) => {
  console.log(detail.widget.id);
  // Note that at this point the widget instance should not be loaded yet but
  // you can now wait for the widgetLoaded event or check if the loaded property is true
  if (!detail.widget.loaded) {
    detail.widget.onEvent('widgetLoaded', () => {});
  }
});

Widget Customization & Settings

You can now fully customize the widget according to your needs. This includes :

  • Partial customization :

    • Arrow design and visibility (mobile & desktop mode),
    • All customization available through the AdAlong interface. Those settings & more are also documented as typescript interface in src/types.ts.
  • Global customization :

    • Controlling the carousel layout : Control the carousel (the media list) to slide back and forth between medias thanks to a public function.
    • Controlling the post viewer : Control the postviewer (the view modal) to slide back and forth between medias thanks to a public function.

All custom settings can be passed during instantiation to override the default settings :

await adalongWidget.load('#widget', {
  ...customSettings,
});

Classes

Some tags have classes starting with "adl-wdgt-" to help styling and customizing. You can also override this prefix by passing a string in the config object when instantiating the widget.

new AdalongWidget('token', {
  classPrefix: 'myPrefix',
});

Control Carousel with custom functions

The AdalongWidget class has some public functions that can be called to control the widget with custom code launched from outisde.

  public getSlideState(): { canSlideLeft: boolean, canSlideRight: boolean } {
    return {
        canSlideLeft: this.storeState.getState().canSlideLeft,
        canSlideRight: this.storeState.getState().canSlideRight,
    }
}

This function will tell you if the carousel is able to slide right or left, thus if there are more images to view in either direction. Then, you can call

 public setSlider(dir: 'left' | 'right') {
    dispatchEvent(new CustomEvent('adalongWidget_slide', {detail: dir}))
}

To trigger a movement in the carousel in the desired direction (by default new images are overflowing on the right).

The last function is to cycle through the elements in the carousel once their thumbnail has been clicked, and the popup with the details is shown:

public changePost(dir: 'left' | 'right') {
dispatchEvent(new CustomEvent('adalongWidget_changePost', { detail: dir }))
}

the 'left' input will open the previous media, while the 'right' input will open the next.

Shop this look

Adding a "shop this look" section

The click on a "shop this look" link will by default open the product url. This behavior can be overridden by providing a function to the shopThisLookHandler field in the config object.

new AdalongWidget('token', {
  shopThisLookHandler: ({ media, product }, targetUrl) => {
    const url = new URL(targetUrl);
    url.searchParams.set('utm_source', 'source');
    url.searchParams.set('utm_medium', 'medium');
    window.open(url.href, '_blank');
  },
});

Customization

You can now fully customize the "shop this look" section according to your needs. This includes :

  • Partial customization :

    • "shop this look" text :

      • shopThisLookText?: string;
    • "more like this" text :

      • moreLikeThisText?: string;
    • arrows and background color, including the possibility to hide arrows in carousel mode, desktop and/or mobile :

      • hideArrows?: boolean;
      • displayMobileCarouselArrows?: boolean;
    • "shop this look" maximum number of columns to be shown :

      • shop_this_look_max_columns?: number;
    • "shop this look" custom product buttons (for ex. to add a "Add to cart" or "Add to favorites" button) : See Shop this look custom product buttons

    • all options directly available through the widget editing tool in our app

partial customization visualization

  • Global customization :

    • Shop this look : When enabled, the "shop this look" section can be entirely replaced by a piece of code of your own creation.

full customization visualization

Shop this look custom product buttons

You can add up to four custom buttons to your products.

This function is called for each product when we have to render and must return an object with react components for rendering the custom buttons. All button events must be handled here following react rules.

Place this function in an object as a parameter of the function AdalongWidget.

 /**
   * @param react The react lib used by AdalongWidget
   * @param product Current rendered product
   * @param media Current opened media
   */
  getCustomProductButtons: (react, product, media) => {
    const addToCart = () =>
      react.createElement(
        'button',
        {
          onClick: () => handleAddToCart(),
        },
        '🛒'
      );
    const addToFavorites = () =>
      react.createElement(
        'button',
        {
          // ... same here
        },
        '♡'
      );
    return {
      topRight: addToCart,
      // each position is optional
      bottomRight: addToFavorites,
    };
  },

You can use four keys to position your custom buttons on the product image : topRight, bottomRight, topLeft, bottomLeft.

If you want to place two buttons next to each other on the product image, you can use react fragments to create a single element :

const twoButtons = () =>
  react.createElement(
    react.Fragment,
    null,
    react.createElement(
      'button',
      {
        onClick: () => handleAddToCart(),
      },
      '🛒'
    ),
    react.createElement(
      'button',
      {
        onClick: () => handleAddToFavorites(),
      },
      '❤️'
    )
  );

Shop This Look entire customization

If you do not want to use the standard "Shop This Look" design, you can entirely customize this section to your needs, thanks to a rendering function called displayCustomShopThisLook.

In this function, you'll insert your piece of react or your react component as well as your logic in order to display it in place of the standard "Shop This Look". This function gives you the possibility to get all products-related info in order to map on it.

Here is a very simple example of the use of this function, by mapping on the products :

 /**
   * @param react The react lib used by AdalongWidget
   * @param products An array containing all related products
   * @param media Current opened media
   * @param isMobile If the widget is viewed in desktop mode (false) or mobile mode (true)
   */
    displayCustomShopThisLook: ({ react, products, media, isMobile, context }) => {
      const { createElement } = react;

      // Optional : Add the "Shop This Look" event tracking function
      const handleProductClick = (product, e) => {
        if (media) {
          context.triggerEvent('shopThisLook', {
            post: media,
            originalEvent: e,
            product: product.id,
          });
        }
      };

      // Map over the products array and create JSX elements for each product
      const productElements = products.map((product) =>
        createElement(
          'div',
          { key: product.id },
          createElement('img', { src: product.image_link, alt: product.title }),
          createElement('h3', null, product.title),
          createElement('p', null, product.description),
          createElement('p', null, `${product.price} ${product.currency}`),
          createElement('a', { href: product.link, onClick: (e) => handleProductClick(product, e), }, 'See the product'),
          createElement('button', null, createElement('i', { className: 'fa fa-heart' }))
        )
      );
      // Return the JSX to be rendered in place of the standard "Shop This Look" section
      return createElement(
        'div',
        null,
        createElement('h2', null, 'Custom Shop This Look'),
        ...productElements
      );
    },

Here is the info you'll receive about a product :

export interface IProduct {
  catalog_id: string;
  company_id: string;
  description: string;
  id: string;
  image_link: string;
  link: string;
  price?: number;
  currency?: string;
  title: string;
  updated_at: string;
  variant_name?: string;
}

Product localization

If you ingested an international catalog, a localization can be set via the AdAlong widget customization interface. This will be the default location for displaying product names, links and pricing information in shop the look. You can override this setting by passing a new location directly as a parameter when the widget is loaded.

adalongWidget.load('#widget', { localization: 'GB' });

⚠️ Please note that the localization names must match those defined during implementation (if in doubt, the list can be viewed via the customization interface).

Facebook Pixel Integration

You can leverage AdAlong widget events in your Facebook Pixel.

Add Facebook Pixel base code

First you have to follow those instructions to create a FB pixel. Once created, you need to add the following base code into the <head> tag of the page. Please note that you should reference your pixel id in two places.

<!-- Facebook Pixel Code -->
<script>
  !(function (f, b, e, v, n, t, s) {
    if (f.fbq) return;
    n = f.fbq = function () {
      n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
    };
    if (!f._fbq) f._fbq = n;
    n.push = n;
    n.loaded = !0;
    n.version = '2.0';
    n.queue = [];
    t = b.createElement(e);
    t.async = !0;
    t.src = v;
    s = b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t, s);
  })(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', '{your-pixel-id-goes-here}');
  fbq('track', 'PageView');
</script>
<noscript>
  <img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id={your-pixel-id-goes-here}&ev=PageView&noscript=1" />
</noscript>
<!-- End Facebook Pixel Code -->

Track Events in your Facebook Pixel

Track standard Facebook events

Now to send information to Facebook from the AdAlong Widget you can map AdAlong events to Facebook standard events:

adalongWidget.onEvent('widgetLoaded', (event) => {
  fbq('track', 'ViewContent', { posts: event.posts });
});

Here is the full documentation on standard Facebook events

Track custom events

Now if you want to track specifically which post has been opened, and not only viewed, Facebook Pixel allows to track custom events following this model:

adalongWidget.onEvent('postOpened', (event) => {
  fbq('trackCustom', 'PostOpened', {
    post: event.post,
    productIds: event.post.products.map(({ id }) => id),
  });
});

Note that in the example we send information about which products the opened post illustrates.

Debugging

Use npm start to build and watch for changes.

Then use npm link to link this repo to another project in which to require the library.

You can also use node debug.js to directly test the library and display it on http://localhost:9800/?apiKey=yourWidgetKey&products=productRef1,productRef2&collections=collectionId1,collectionId2