JSFiddle - React, Tailwind, and code Playground

by lega911

HTML

<script src="https://angularlight.org/bin/alight_0.14.last.min.js"></script>
<h2>list navigator demo</h2>

<list-navigator :source="list" :initselected="::selected" @changed="selected=$value" :ctx="this">
  <div class="item-container" :class.item-container-selected="selected[i.id]">
    <div class="item-header" :class.item-header-archived="i.archived">
      {{i.firstName}} {{i.lastName}}
      <button al-if="!i.archived" class="btn-arch" @click="ctx.onArchive(i)">Archive</button>
    </div>
    <div class="item-details">
      Id: {{i.id}}, Email: {{i.email}}, Gender: <span class="item-details-gender-{{i.gender.toLowerCase()}}">{{i.gender}}</span>
    </div>
  </div>
</list-navigator>

<div>
  Selected: {{getSelectedUsersText()}}
</div>



<template id="navigator-tpl">
  <div al-repeat="i in toDisplay()">
      <div class="cb-wrapper">
          <input type="checkbox" al-model="selected[i.id]" @change="onSelectedChange()"/>
      </div>
      <div class="item-wrapper" :html="itemTpl"></div>
  </div>
  <div>
      <button @click="onPrev()" :disabled="firstPage()">Prev</button>
      <button @click="onNext()" :disabled="lastPage()">Next</button>
  </div>  
</template>

CSS

body {
    font-family: 'Segoe UI', sans-serif;
}

span {
    font-style: italic;
}

.item-container {
    margin: 8px;
    padding: 8px;
    width: 450px;
    border: 1px solid darkslategrey;
    border-radius: 5px;
}

.item-header {
    font-size: 1.3rem;
}

.item-container-selected .item-header {
    font-weight: bold;    
}


.item-details {
    color: dimgrey;
    font-size: 0.9rem;
}

.item-details-gender-male {
    color: blue;
}

.item-details-gender-female {
    color:deeppink;
}

.cb-wrapper {
  display: inline-block;
}
.item-wrapper {
  display: inline-block;
}
.item-header-archived{
  color: lightgray;
}

.btn-arch{
  background-color: white;
  border: 2px solid lightgray;
  float: right;
}

.btn-arch:hover{
  border-color: 2px solid gray;
  background-color: gainsboro;
}

Babel + JSX

alight.component('list-navigator', function(scope, element) {
	scope.itemTpl = element.innerHTML;
	scope.onSelectedChange = () => scope.$sendEvent('changed', scope.source.filter((i) => scope.selected[i.id]));
  scope.selected = {};
  var page = 0;
  scope.onPrev = () => page--;
  scope.onNext = () => page++;
  scope.firstPage = () => page < 1;
  scope.lastPage = () => page*5+5>=scope.source.length;
  scope.toDisplay = () => scope.source.slice(page*5, page*5 + 5);
  
	return {
  	templateId: 'navigator-tpl',
    onStart: () => {
    	for(let i of scope.initselected)
    		scope.selected[i.id] = true;
    }
  }
});

var app = {
	list: listOfUsers(),
  selected: listOfUsers().slice(1, 3),
  getSelectedUsersText: () => app.selected.map((i) => i.firstName + ' ' + i.lastName).join(','),
  onArchive: (i) => i.archived = true
};

alight('body', app);








////////////////////////////////////////////////

function listOfUsers() {
	return [{ "id": 1, "firstName": "Stephanie", "lastName": "Owens", "email": "sowens0@cmu.edu", "gender": "Female" }, { "id": 2, "firstName": "Stephen", "lastName": "Torres", "email": "storres1@cbc.ca", "gender": "Male" }, { "id": 3, "firstName": "Lillian", "lastName": "West", "email": "lwest2@jalbum.net", "gender": "Female" }, { "id": 4, "firstName": "Larry", "lastName": "Hill", "email": "lhill3@phpbb.com", "gender": "Male" }, { "id": 5, "firstName": "Patrick", "lastName": "Duncan", "email": "pduncan4@prlog.org", "gender": "Male" }, { "id": 6, "firstName": "Steven", "lastName": "Nguyen", "email": "snguyen5@meetup.com", "gender": "Male" }, { "id": 7, "firstName": "Eugene", "lastName": "Garrett", "email": "egarrett6@psu.edu", "gender": "Male" }, { "id": 8, "firstName": "Juan", "lastName": "Wood", "email": "jwood7@elpais.com", "gender": "Male" }, { "id": 9, "firstName": "Harold", "lastName": "Little", "email": "hlittle8@walmart.com", "gender": "Male" }, { "id": 10, "firstName": "Linda", "lastName": "Cunningham", "email":...