A rewrite of Anura from the ground up using webcomponents. No jQuery, no npm, just plain ES6. Goals:

  • framework-agnostic (no node, no angular, no react)
  • source-agnostic (work with multiple DAM systems)
  • furthermore, it should be
    • easy to integrate
    • accessible
    • responsive

Internet Explorer is NOT supported anymore. If you need that, use the jQuery one (and may god have mercy upon your soul)

Demo

See https://anura.brix.ch/webcomponents.

Installation

Anura is available via

  • git submodule (ask us for a user)
    • git submodule add https://gitlab.brix.ch/brix/celum/anura/webcomponents.git lib/anura
    • and to update git submodule update --remote
  • npm
    • npm i anura-webcomponents
  • unpkg CDN
    • <script type="module" src="https://unpkg.com/anura-webcomponents/src/adapters/$DAM-adapter.js"></script>
    • <script type="module" src="https://unpkg.com/anura-webcomponents/src/components/anura-components.js"></script>

Usage

You'll want to be more selective than simply loading all adapters via the index.js -> replace $DAM with bynder, celum or sharedien:

<head>
  <script type="module" src="lib/anura/src/adapters/$DAM-adapter.js"></script>
  <script type="module" src="lib/anura/src/components/anura-components.js"></script>
</head>

The same applies to anura-components.js, you might only want to load a specific one, e.g. anura-table.js

Introduction

Webcomponents are declarative, so where before you needed custom Javascript, you now just:

<anura-gallery node="123"></anura-gallery>

In order to abstract away the source of your assets, the concept of adapters exists. These hold common settings (such as the locale) and know how to talk to a source (usually a DAM). They are hooked up as follows:

<some-adapter url="https://my.server.com/anura/example" locale="de"></some-adapter>
<anura-gallery adapter="some-adapter" node="123"></anura-gallery>

Note that you can update locale at runtime, and the gallery will reload itself to reflect that change.

To use multiple adapters at the same time: give them an ID like id=my-id, and refer to them as adapter="#my-id".

The same applies to hooking up different components to one another. Here's an example with a navigation tree:

<some-adapter url="https://my.server.com/anura/example" locale="de"></some-adapter>
<div style="display: flex">
    <anura-tree adapter="some-adapter" root="1337"></anura-tree>
    <anura-gallery adapter="some-adapter" search="anura-tree"></anura-gallery>
</div>

The tree is configured as the search component for the gallery, so it will now listen to navigation events and update itself.

Screenshot of anura-tree and anura-gallery side-by-side

Page Anatomy

When composing your own anura page, you will use a variety of different anura components, which you can mix-and-match alongside regular HTML as you see fit. For example:

graphic of an anura page layout

Using just 4 different anura-components, we can simply create an easy-to-use media browsing experience - anywhere in the web!

screenshot of a basic anura page

In order for this to work, we need to hook them up to one another like so (note the adapter and source attributes):

<html lang="en">
<head>
    <script type="module" src="adapters/some-adapter.js"></script>
    <script type="module" src="components/anura-*.js"></script><!-- more imports here -->
    <!-- style omitted for brevity -->
</head>
<body>
    <header>
        <h1>Media Database</h1>
        <anura-basket adapter="some-adapter"></anura-basket>
    </header>

    <some-adapter url="https://some.place"></some-adapter>

    <aside>
        <anura-searchbar adapter="some-adapter"></anura-searchbar>
        <anura-select adapter="some-adapter" source="Season"></anura-select>
        <anura-select adapter="some-adapter" source="Location"></anura-select>
        <anura-select adapter="some-adapter" source="Copyright"></anura-select>
    </aside>
    <main>
        <anura-gallery adapter="some-adapter" search="anura-searchbar,anura-select" basket="anura-basket"></anura-gallery>
    </main>
</body>
</html>

Also note how components can contain other components, such as <anura-asset> inside the gallery (done automatically, unless you specify something else in that slot).

Component Anatomy

Every component usually has:

  • Attributes: HTML attributes on component-level, such as locale="de" that can be updated "live" at any time. These can either be configured, or they appear as a result of an interaction, e.g. anura-tree will update its value attribute when a node has been selected.
  • Events: Emitted (or consumed) when something interactive happens, e.g. clicking on a node anura-tree yields a node-selected-event.
  • Slots: Places to add you own HTML into the component, e.g. anura-tree has a slot for a title, so you can <anura-tree><h3 slot="title">my custom title</h3></anura-tree>.
  • Parts: Named parts of components that are available for styling, e.g. anura-gallery::part(asset-title) { color: #f00 } to make an assets title red. Note that unnamed shadow DOM objects are not styleable (by design).
  • Variables: CSS-variables allow you to specify some global default, without having to touch each part, e.g. --button-color: blue.

Integration

In the Introduction we said that we can change the locale at runtime (or any other attribute marked live: yes). Let's do that:

In JavaScript

Example: change the locale attribute using an regular dropdown:

<some-adapter locale="de"></some-adapter>

<label for="demo">Language</label>
<select id="demo" onchange="document.querySelector('some-adapter').setAttribute('locale', event.target.value)">
    <option value="de" selected>Deutsch</option>
    <option value="en">English</option>
</select>

In Angular

Example: change the locale attribute using an external dropdown (mat-select in this case):

<some-adapter [attr.locale]="selectedLanguage"></some-adapter>

<mat-form-field appearance="fill">
  <mat-label>Language</mat-label>
  <mat-select [(value)]="selectedLanguage">
    <mat-option value="de">Deutsch</mat-option>
    <mat-option value="en">English</mat-option>
  </mat-select>
</mat-form-field>

Further reading