1
0
mirror of https://github.com/garraflavatra/rolens.git synced 2025-01-19 05:27:57 +00:00
rolens/frontend/src/components/grid.svelte

168 lines
3.5 KiB
Svelte
Raw Normal View History

2023-01-10 16:28:27 +00:00
<script>
import { createEventDispatcher } from 'svelte';
import Icon from './icon.svelte';
export let columns = [];
export let items = [];
export let key = 'id';
export let activeKey = '';
export let activeChildKey = '';
export let showHeaders = true;
export let level = 0;
export let contained = false;
const dispatch = createEventDispatcher();
const childrenOpen = {};
$: _items = objectToArray(items).map(item => {
item.children = objectToArray(item.children);
return item;
});
function objectToArray(obj) {
if (Array.isArray(obj)) {
return obj;
}
else if (typeof obj === 'object') {
return Object.entries(obj).map(([ k, item ]) => ({ ...item, [key]: k }));
}
else {
return obj;
}
}
function select(itemKey) {
activeKey = itemKey;
activeChildKey = '';
dispatch('select', itemKey);
}
function selectChild(itemKey, childKey) {
select(itemKey);
activeChildKey = childKey;
dispatch('selectChild', childKey);
}
function toggleChildren(itemKey) {
childrenOpen[itemKey] = !childrenOpen[itemKey];
}
</script>
<div class:grid={level === 0} class:subgrid={level > 0} class:contained>
<table>
{#if showHeaders && columns.some(col => col.title)}
<thead>
<tr>
<th class="has-toggle"></th>
{#each columns as column}
<th scope="col">{column.title || ''}</th>
{/each}
</tr>
</thead>
{/if}
<tbody>
{#each _items as item (item[key])}
<tr on:click={() => select(item[key])} class:selected={activeKey === item[key] && !activeChildKey}>
<td class="has-toggle">
2023-01-10 19:10:39 +00:00
{#if item.children?.length}
2023-01-10 16:28:27 +00:00
<button class="toggle" on:click={() => toggleChildren(item[key])}>
<Icon name={childrenOpen[item[key]] ? 'chev-d' : 'chev-r'} />
</button>
{/if}
</td>
{#each columns as column}
{@const value = item[column.key]}
<td class:right={column.right}>
{#if typeof value !== 'object'}
{value || ''}
{/if}
</td>
{/each}
</tr>
{#if item.children && childrenOpen[item[key]]}
<tr>
<td></td>
<td colspan={columns.length + 1} class="subgrid-parent">
<svelte:self
{columns}
{key}
bind:activeKey={activeChildKey}
showHeaders={false}
items={item.children}
level={level + 1}
on:select={e => selectChild(item[key], e.detail)}
/>
</td>
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
<style>
.grid {
width: 100%;
2023-01-11 19:41:15 +00:00
height: 100%;
2023-01-13 15:56:48 +00:00
background-color: #fff;
2023-01-10 16:28:27 +00:00
}
.grid.contained {
border: 1px solid #ccc;
}
.subgrid {
width: 100%;
}
table {
border-collapse: collapse;
width: 100%;
}
table thead {
border-bottom: 2px solid #ccc;
}
2023-01-10 19:10:39 +00:00
th {
2023-01-10 16:28:27 +00:00
font-weight: 600;
text-align: left;
}
tr {
cursor: pointer;
}
td, th {
padding: 0.3rem;
}
td.has-toggle {
width: calc(20px + 0.3rem);
}
td.subgrid-parent {
padding: 0;
}
2023-01-10 19:10:39 +00:00
tbody tr.selected td {
2023-01-10 16:28:27 +00:00
background-color: #00008b;
color: #fff;
}
button.toggle {
color: inherit;
padding: 0;
2023-01-13 15:56:48 +00:00
margin: 0;
display: contents;
2023-01-10 16:28:27 +00:00
}
button.toggle :global(svg) {
width: 15px;
height: 15px;
vertical-align: top;
}
.right {
text-align: right;
}
</style>