trieur.

In markup, without writing JS

Zones and the card template are declared in HTML. The only JS left is the pile β€” and that comes from your data anyway. Add, change or remove a <trieur-zone> mid-session: the stage follows without starting over, the current pile and the undo history survive.

dev ai home to read
<trieur-deck id="sorter" layout="voronoi" threshold="80" multi
             tap-zones="false" touch-preview="false">
  <trieur-zone value="dev" key="a" icon="⌘" color="#4a54f2">dev</trieur-zone>
  <trieur-zone value="ai" icon="β—‘">ai</trieur-zone>
  <trieur-zone></trieur-zone><!-- free zone: dropping fires trieur:assign -->

  <template data-card>
    <div class="link">
      <span class="host" data-field="host"></span>
      <h4 data-field="title"></h4>
      <img data-field="image" data-attr="src" alt="" />
    </div>
  </template>
</trieur-deck>

<script type="module">
  import '@trieur/core/element';
  sorter.items = links;                    // JS always wins over markup
  sorter.addEventListener('trieur:sort', (e) => console.log(e.detail.item, e.detail.zones));
</script>

No shadow DOM, deliberately: you draw the cards, so your styles have to reach them. The stage lives in a child of the custom element, so the library can rewrite its container without erasing the <trieur-zone> elements that are its configuration.

Keyboard and gestures

Sorting

File into a zone
a s d … or drag the card there
Accept the model's suggestion
Skip β€” back of the pile
Undo, and unlearn it
Fullscreen
the bar button; Esc leaves

Touch

Accept the suggestion
double tap the card