Contacts, Menus, Tables

Contacts List, Menu List and Data Table

A contacts list is a grouped list with the contacts-list class, which restyles the group titles: a 22 px bar on iOS, a letter in a 40 px left column on Material (List Index's screenshot). Grouped by genre, that column printed "Home and Garden" over the book titles, so /genres/ uses a plain grouped list (list list-strong, same markup), whose titles stick to the top as their group scrolls.

A menu list (list menu-list) marks the current choice with item-selected on its item-link, like a vertical tab bar; on /genres/ its three rows set a stock filter.

A data table is a <table> inside .card.data-table, with label-cell and right-aligned numeric-cell columns. On /stock/, Price and Rating are sortable-cell headers and the wrapper has data-table-init, without which header clicks did nothing. Framework7 572,986 then toggles sortable-cell-active and sortable-asc/sortable-desc and fires datatable:sort, but never reorders the rows. That part is yours:

Sorting the stock table's rows in src/pages/stock.f7
$el.value.find('.sortable-cell').on('datatable:sort', (e) => {
  const key = e.target.dataset.key;
  const dir = e.detail === 'desc' ? -1 : 1;
  rows.sort((a, b) => dir * (a[key] - b[key]));
  console.log(`sort ${key} ${e.detail}:`, rows.map((b) => b.id).join(', '));
  $update();
});

Clicking Price twice printed:

Output of 41
sort price asc: 1, 5, 4, 6, 3, 2
sort price desc: 2, 3, 6, 4, 5, 1
The genres page in iOS, filtered to "In stock" in Material, and the stock table sorted by price
The genres page in iOS, filtered to "In stock" in Material, and the stock table sorted by price

The header keeps its sort classes across $update() because the template's class attributes don't change, so the virtual DOM leaves Framework7's additions alone.