Examples

Assembly

A fully assembled demo page, featuring a tree and a gallery (with something configured in every slot)

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Anura Webcomponents Example</title>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="module" src="adapters/some-adapter.js"></script>
    <script type="module" src="components/anura-components.js"></script>
</head>
<body>

<some-adapter url="https://my.server.io/api" locale="de"></some-adapter>

<div style="display: flex">
    <aside aria-label="Navigation">
        <anura-tree adapter="some-adapter" show-root="true" depth="1" root="1737" selected="1738" icon="archive" aria-live="polite"></anura-tree>
    </aside>
    <main aria-label="Gallery">
        <anura-counter parent="anura-gallery"></anura-counter>
        <anura-gallery adapter="some-adapter" search="anura-tree" page-size="32" aria-live="polite">
            <anura-asset slot="asset" buttons="download,checkbox,info" quick-download="1"></anura-asset>
            <anura-paginator slot="paginator" mode="auto" detect-scroll="false"></anura-paginator>
        </anura-gallery>
        <anura-lightbox buttons="fullscreen,sidebar,close">
            <anura-details slot="sidebar" allowlist="id,name,info_102,info_103"></anura-details>
        </anura-lightbox>
    </main>
</div>
</body>
</html>

View switcher

Offer different view components for the same content. The key here is to set the other views as disabled.

<some-adapter url="https://my.server.io/api" locale="de"></some-adapter>

<select id="demo-switcher">
    <option value="anura-gallery">Gallery</option>
    <option value="anura-table">Table</option>
    <option value="anura-map">Map</option>
</select>

<anura-gallery adapter="some-adapter" source="omitted" class="main-view"></anura-gallery>
<anura-table   adapter="some-adapter" source="omitted" class="main-view" disabled></anura-table>
<anura-map     adapter="some-adapter" source="omitted" class="main-view" disabled></anura-map>

<script>
    document.querySelector('#demo-switcher').addEventListener('change', e => {
        document.querySelectorAll('.main-view').forEach(view => view.setAttribute('disabled', ''));
        document.querySelector(e.target.value).removeAttribute('disabled');
    });
</script>

Disabled components do not react to source updates (and get aria-hidden). Once re-enabled, the sources are queried again to update the content.

Hidden search restrictions

In order to scope all search requests to a particular subsection of your DAM, you can declare <input type="hidden"> along your other <anura-xyz>, e.g. to only show assets below node 123:

<aside id="my-search">
    <anura-searchbar some="options">
    <anura-select more="options">
    <anura-select more="options">
    <input type="hidden" value="search_node=123"><!-- the exact syntax of "value" will depend on your DAM -->
</aside>
<anura-gallery search="#my-search > *">

(again, please use permissions to restrict what the user has access to in general, as it would be trivial to simply remove the <input>)

Dynamic endpoints

Suppose you are using the same layout, but various endpoints to display different assets, depending on a URL parameter.

Let's say https://my.page.com/products.html#sales-country=ch and https://my.page.com/products.html#sales-country=de

Due to the nature of the adapters, they will require their URL to be set when they load, which you can achieve with:

<some-adapter url="https://my.server.com"></some-adapter>
<script>
  customElements.whenDefined('some-adapter').then(() => {
    const adapter = document.querySelector('some-adapter');
    const baseUrl = adapter.getAttribute('url'); // = 'https://my.server.com'
    adapter.setAttribute('url', `${baseUrl}/anura/${adapter.getState('sales', 'country')}`);
  });
</script>

... this will set the url attribute to https://my.server.com/anura/ch or https://my.server.com/anura/de depending on #sales-country.

Content Slot (string interpolation)

anura-asset offers a content slot to put additional information, be that asset markers (aka bullets) or more text.

The following snippet demonstrates both, the span creates a file extension bullet "JPG", the p adds a description line beneath (taken from a metadata field of that name):

<anura-gallery ...>
    <anura-asset slot="asset" ...>
        <span slot="content">
            <span class="asset-marker" style="color: white; position: absolute; bottom: 37%; right: 3%; background: rgba(0, 34, 51, 0.4); padding: 2px 5px; border-radius: 2px; font-size: 0.8rem; text-transform: uppercase;">
                ${asset.fileExtension}
            </span>
            <p if="${asset.metadata[description].value}" class="description" style="font-size: 85%; margin: 0.25rem 0;">
                ${asset.metadata[description].name}: ${asset.metadata[description].value}
            </p>
        </span>
    </anura-asset>
</anura-gallery>

Note how you can add an if attribute to any sub-node, so that you don't get a "Description: " with no actual value to display (removes the node when empty). This yields:

screenshot of the content slot

While if simply checks if any value is present, you may also use equals and contains as conditional attributes, e.g.

<span if="${asset.metadata[copyright].value}" contains="copyrighted">
    <img src="img/copyright-symbol.svg">
</span>

Post-processing

A small set of post-processing commands are available through the | symbol, e.g. ${asset.metadata[description].value | trim}. Known commands:

  • split - expects 2 arguments, the separation character and which part you'd like back (zero-based). Suppose you only need the first sentence in asset.metadata[description].value, you'd write ${asset.metadata[description].value | split . 0}.
  • trim - trims excessive whitespace from wither end of a string (takes no arguments).

Button Slots

anura-asset and anura-lightbox both offer a slot called buttons where you can place custom buttons. Let's add one for each inside of a gallery (with a simple alert()):

<anura-gallery adapter="some-adapter">
    <anura-asset slot="asset" buttons="basket,info">
        <span slot="buttons">
            <button onclick="alert('Asset '+this.value)" title="demo" style="background: none; border: none; padding: 0">
                <anura-icon icon="alert-triangle"></anura-icon>
            </button>
        </span>
    </anura-asset>
</anura-gallery>
<anura-lightbox buttons="basket,sidebar,close">
    <span slot="buttons">
        <button onclick="alert('Lightbox asset '+this.value)" title="demo" style="background: none; border: none; padding: 0; margin: 1.5rem">
            <anura-icon icon="alert-triangle"></anura-icon>
        </button>
    </span>
</anura-lightbox>

Note how the value of the click event provides you the ID of the current asset. We'd also advise to use an anura-icon inside for consistency.

Variable Scopes

When changing a variable, it may be necessary to inform more than one party. This is a limitation of parts and can be addressed by telling both components (in this case anura-gallery and the anura-asset inside of it):

anura-gallery, anura-gallery::part(anura-asset) {
    --asset-width: 15rem;
    --asset-height: 15rem;
}

Variables + Parts + String Interpolation

To demonstrate what you can achieve through variables, parts and string interpolation, suppose we want a gallery with wide assets, in order to show more details upfront. In other words, we want to go from this:

screenshot of the regular gallery

... to this:

screenshot of a wide gallery

Which we can easily achieve using 2 variables, 3 parts and 4 table rows:

<head>
    <script type="module" src="components/..."></script>
    <style>
        anura-gallery, anura-gallery::part(anura-asset) {
            --asset-width: 25rem; /* change aspect ratio */
            --asset-height: 8rem;
            flex-direction: row; /* move content to the right */
        }
        anura-gallery::part(asset-figure) {
            width: 33%; /* shrink the thumbnail */
            margin-right: 2%;
            height: 100%;
        }
        anura-gallery::part(asset-title) {
            display: none; /* no figcaption */
        }
    </style>
</head>
<body>
    <some-adapter url="https://..." infofields="127,128,160"></some-adapter>
    <anura-gallery adapter="some-adapter" aria-live="polite">
        <anura-asset slot="asset">
            <span slot="content">
                <table style="font-size: 90%">
                    <tr>
                        <td>Name:</td>
                        <td>${asset.name}</td><!-- interpolate ${} -->
                    </tr>
                    <tr if="${asset.metadata[info_160].value}"> <!-- hide the row if value is empty -->
                        <td>${asset.metadata[info_160].name}:</td>
                        <td>${asset.metadata[info_160].value}</td>
                    </tr>
                    <tr if="${asset.metadata[info_128].value}">
                        <td>${asset.metadata[info_128].name}:</td>
                        <td>${asset.metadata[info_128].value}</td>
                    </tr>
                    <tr if="${asset.metadata[info_127].value}">
                        <td>${asset.metadata[info_127].name}:</td>
                        <td>${asset.metadata[info_127].value}</td>
                    </tr>
                </table>
            </span>
        </anura-asset>
    </anura-gallery>
</body>