Added Roles, User Management, fixed bugs, added FlexTable component (should be renamed to GridTable), other table components and test code should be removed down the line, added admin function to fix broken data structures.
This commit is contained in:
181
imports/ui/TestUsers.svelte
Normal file
181
imports/ui/TestUsers.svelte
Normal file
@@ -0,0 +1,181 @@
|
||||
<script>
|
||||
export let rows;
|
||||
export let columns;
|
||||
export let rowKey;
|
||||
export let edited;
|
||||
|
||||
// Setup a width for each column.
|
||||
columns.forEach(column => {
|
||||
let min = column.minWidth ? Math.max(10, column.minWidth) : 10;
|
||||
let weight = column.weight ? Math.max(1, column.weight) : 1;
|
||||
column.width = 'minmax(' + min + 'px, ' + weight + 'fr)';
|
||||
});
|
||||
let gridTemplateColumns = columns.map(({width}) => width).join(' ');
|
||||
|
||||
let headerBeingResized = null;
|
||||
let horizontalScrollOffset = 0;
|
||||
const initResize = ({target}) => {
|
||||
headerBeingResized = target.parentNode;
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.addEventListener('mouseup', completeResize);
|
||||
headerBeingResized.classList.add('header--being-resized');
|
||||
};
|
||||
const completeResize = () => {
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('mouseup', completeResize);
|
||||
headerBeingResized.classList.remove('header--being-resized');
|
||||
headerBeingResized = null;
|
||||
};
|
||||
const onMouseMove = e => {
|
||||
try {
|
||||
// Calculate the desired width.
|
||||
horizontalScrollOffset = document.documentElement.scrollLeft;
|
||||
let parentX = Math.round(headerBeingResized.getBoundingClientRect().x);
|
||||
const width = horizontalScrollOffset + (e.clientX - parentX);
|
||||
// Update the column object with the new size value.
|
||||
const column = columns.find(({element}) => element === headerBeingResized);
|
||||
column.width = Math.max(column.minWidth, width) + "px";
|
||||
// Ensure all the column widths are converted to fixed sizes.
|
||||
columns.forEach((column, index) => {
|
||||
if((index < columns.length - 1) && (column.width.startsWith('minmax'))) {
|
||||
column.width = parseInt(column.element.clientWidth, 10) + 'px';
|
||||
}
|
||||
});
|
||||
// Render the new column sizes.
|
||||
gridTemplateColumns = columns.map(({width}) => width).join(' ');
|
||||
} catch(e) {console.log(e);}
|
||||
}
|
||||
|
||||
let selectedRowElement = null;
|
||||
const selectRow = (e, row) => {
|
||||
let element = e.target;
|
||||
|
||||
while(element && element.nodeName !== "TR") element = element.parentNode;
|
||||
|
||||
if(selectedRowElement) {
|
||||
selectedRowElement.classList.remove('selected');
|
||||
}
|
||||
|
||||
selectedRowElement = element;
|
||||
element.classList.add('selected');
|
||||
}
|
||||
|
||||
let editorContainer;
|
||||
const editRow = (e, row) => {
|
||||
let element = e.target;
|
||||
while(element && element.nodeName !== "TR") element = element.parentNode;
|
||||
let editor = element.querySelector('.editor');
|
||||
|
||||
// Save the edited row so the editor has access to it.
|
||||
$edited = row;
|
||||
|
||||
if(editor) {
|
||||
editor.appendChild(editorContainer);
|
||||
}
|
||||
editorContainer.classList.remove('hidden');
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={editorContainer} class="hidden"><slot>Slot</slot></div>
|
||||
<table style="--grid-template-columns: {gridTemplateColumns}">
|
||||
<thead>
|
||||
<tr>
|
||||
{#each columns as column}
|
||||
<th bind:this={column.element}>{column.title} <span class="resize-handle" on:mousedown={initResize}></span></th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each $rows as row (rowKey(row))}
|
||||
<!-- data-key="{rowKey(row)}"-->
|
||||
<tr class:hidden={row === $edited} on:mousedown={(e) => selectRow(e, row)} on:dblclick={(e) => editRow(e, row)}>
|
||||
{#each columns as column}
|
||||
<td>{column.value(row)}</td>
|
||||
{/each}
|
||||
<td class="editor"></td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<button on:click={() => {$edited = null}} type="button">Stop Editing</button>
|
||||
|
||||
<style>
|
||||
table {
|
||||
width: auto;
|
||||
-webkit-box-flex: 1;
|
||||
flex: 1;
|
||||
display: grid;
|
||||
border-collapse: collapse;
|
||||
grid-template-columns: var(--grid-template-columns);
|
||||
}
|
||||
thead, tbody, tr {
|
||||
display: contents;
|
||||
}
|
||||
th, td {
|
||||
padding: 15px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
}
|
||||
th {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: #5cb85c;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
font-size: 1.1rem;
|
||||
color: white;
|
||||
position: relative;
|
||||
}
|
||||
th:last-child {
|
||||
border: 0;
|
||||
}
|
||||
.resize-handle {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: black;
|
||||
opacity: 0;
|
||||
width: 3px;
|
||||
cursor: col-resize;
|
||||
}
|
||||
th:last-child .resize-handle {
|
||||
display: none;
|
||||
}
|
||||
.resize-handle:hover, .header--being-resized .resize-handle {
|
||||
opacity: 0.5;
|
||||
}
|
||||
th:hover .resize-handle {
|
||||
opacity: 0.3;
|
||||
}
|
||||
td {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
color: #808080;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background: #f8f6ff;
|
||||
}
|
||||
:global(.selected), :global(.selected) > td {
|
||||
background-color: yellow;
|
||||
}
|
||||
.editor {
|
||||
grid-column: 1 / 4;
|
||||
display: none;
|
||||
}
|
||||
/*:global(td.hidden) {*/
|
||||
/* display: none;*/
|
||||
/*}*/
|
||||
:global(tr.hidden) > td:not(.editor) {
|
||||
display: none !important;
|
||||
}
|
||||
:global(tr.hidden) > td.editor {
|
||||
display: block !important;
|
||||
}
|
||||
:global(div.hidden) {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user