This is the template project that's checked out and configured when you run the bando-up command from ljsthw-bandolier. This is where the code really lives.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bandolier-template/client/components/DataTable.svelte

179 lines
4.2 KiB

<script>
import { onMount, createEventDispatcher } from 'svelte';
import Icon from "./Icon.svelte";
import Pagination from "./Pagination.svelte";
export let rows = [];
export let columns = [];
export let pagination = { currentPage: 1, lastPage: 1 }
let search_text = "";
let sort_order = 1;
let sort_column = "";
let dispatch = createEventDispatcher();
const clear_search = async () => {
search_text = "";
dispatch("clear_search");
}
const search_query = async () => {
dispatch("search_query", search_text);
}
const handle_keypress = (event) => {
if(event.key === "Enter") {
dispatch("search_query", search_text);
} else if(event.key === "Escape") {
dispatch("clear_search");
}
}
const cell_click = (row, column, name) => {
dispatch("cell_click", {row, column, name});
}
const sort_by = (name) => {
if(name == sort_column) {
// clicking the same column so just invert the sort order
sort_order *= -1;
} else {
// new column, reset sort order and name
sort_order = 1;
sort_column = name;
}
rows = rows.sort((a, b) => {
let cola = a[sort_column];
let colb = b[sort_column];
if(cola < colb) {
return sort_order * -1;
} else if(cola > colb) {
return Number(sort_order);
} else {
return 0;
}
});
}
const page_changed = (change) => {
dispatch("full_query", change);
}
</script>
<style>
buttons {
display: flex;
flex-direction: row;
flex-wrap: none;
justify-content: space-evenly;
width: 100%;
}
buttons left,
buttons right {
display: flex;
justify-content: space-evenly;
align-items: center;
width: 100%;
}
buttons left paging {
flex-grow: 2;
flex-direction: row-reverse;
}
table {
width: 100%;
}
tr,
td {
width: min-content;
}
td {
outline: 1px solid var(--color-border);
text-align: left;
}
td:hover {
outline: 1px solid var(--color-bg-inverted);
}
tr:nth-child(even) {
background-color: var(--color-bg-tertiary);
}
data-table {
overflow: auto;
max-width: 98vw;
min-width: 98vw;
width: 98vw;
}
</style>
<svelte:window on:keypress={ handle_keypress }/>
<buttons>
<left>
<slot></slot>
<paging>
<Pagination bind:pagination on:change={ page_changed } />
</paging>
</left>
<right>
<input id="search" bind:value={ search_text} name="search" placeholder="Search ..." type="text" />
<span on:click={ search_query } ><Icon name="search" tooltip="Search." size="36" /></span>
<span on:click={ clear_search }><Icon name="x-circle" tip_position="bottom-left" tooltip="Clear search." size="36" /></span>
</right>
</buttons>
<data-table>
{#if rows.length === 0}
<h1 data-testid="nothing-found">Nothing Found</h1>
<p>The table returned no results for your search text <em>{ search_text }</em>. You can use ESC to clear the search.</p>
{:else}
<table>
<thead>
<tr>
{#each columns as name}
{#if name !== "_url"}
<th on:click={ () => sort_by(name) }>{ name }
{#if sort_column === name && sort_order === 1}
<Icon name="arrow-down" size="18" color="var(--color-text-inverted)" />
{:else if sort_column === name && sort_order === -1}
<Icon name="arrow-up" size="18" color="var(--color-text-inverted)" />
{/if}
</th>
{/if}
{/each}
</tr>
</thead>
<tbody>
{#each rows as row, i}
<tr>
{#each columns as name, j}
{#if name === "id"}
<td on:click={ () => cell_click(i, j, name) }>
{#if row._url}
<a data-testid="row-{i}" href={ row._url }>{ row[name] }</a>
{:else}
{ row[name] }
{/if}
</td>
{:else if name !== "_url"}
<td on:click={ () => cell_click(i, j, name) }>{ row[name] }</td>
{/if}
{/each}
</tr>
{/each}
</tbody>
</table>
{/if}
</data-table>