mirror of
https://github.com/dbgate/dbgate
synced 2024-11-08 04:35:58 +00:00
scrollable change list
This commit is contained in:
parent
e203d34aed
commit
819fdac8ab
204
packages/web/src/elements/ScrollableTableControl.svelte
Normal file
204
packages/web/src/elements/ScrollableTableControl.svelte
Normal file
@ -0,0 +1,204 @@
|
||||
<script lang="ts" context="module">
|
||||
export interface TableControlColumn {
|
||||
fieldName: string;
|
||||
header: string;
|
||||
component?: any;
|
||||
getProps?: any;
|
||||
formatter?: any;
|
||||
slot?: number;
|
||||
isHighlighted?: Function;
|
||||
width?: string;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import keycodes from '../utility/keycodes';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import resizeObserver from '../utility/resizeObserver';
|
||||
|
||||
export let columns: TableControlColumn[];
|
||||
export let rows;
|
||||
export let focusOnCreate = false;
|
||||
export let selectable = false;
|
||||
export let selectedIndex = 0;
|
||||
export let clickable = false;
|
||||
export let disableFocusOutline = false;
|
||||
|
||||
export let domTable = undefined;
|
||||
|
||||
let clientHeight = 0;
|
||||
let headerHeight = 0;
|
||||
let domBody;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: columnList = _.compact(_.flatten(columns));
|
||||
|
||||
onMount(() => {
|
||||
if (focusOnCreate) domTable.focus();
|
||||
});
|
||||
|
||||
const handleKeyDown = event => {
|
||||
if (event.keyCode == keycodes.downArrow) {
|
||||
selectedIndex = Math.min(selectedIndex + 1, rows.length - 1);
|
||||
}
|
||||
if (event.keyCode == keycodes.upArrow) {
|
||||
selectedIndex = Math.max(0, selectedIndex - 1);
|
||||
}
|
||||
};
|
||||
|
||||
function scrollToIndex(index) {
|
||||
if (!domBody) return;
|
||||
const element = domBody.children[index];
|
||||
if (element) element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
||||
}
|
||||
|
||||
$: scrollToIndex(selectedIndex);
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="wrapper"
|
||||
use:resizeObserver={true}
|
||||
on:resize={e => {
|
||||
// @ts-ignore
|
||||
clientHeight = e.detail.height;
|
||||
}}
|
||||
>
|
||||
<table
|
||||
bind:this={domTable}
|
||||
class:selectable
|
||||
class:disableFocusOutline
|
||||
on:keydown
|
||||
tabindex={selectable ? -1 : undefined}
|
||||
on:keydown={handleKeyDown}
|
||||
>
|
||||
<thead
|
||||
use:resizeObserver={true}
|
||||
on:resize={e => {
|
||||
// @ts-ignore
|
||||
headerHeight = e.detail.height;
|
||||
}}
|
||||
>
|
||||
<tr>
|
||||
{#each columnList as col}
|
||||
<td style={col.width ? `width: ${col.width}` : undefined}>{col.header || ''}</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style={`max-height: ${clientHeight - headerHeight}px`} bind:this={domBody}>
|
||||
{#each rows as row, index}
|
||||
<tr
|
||||
class:selected={selectable && selectedIndex == index}
|
||||
class:clickable
|
||||
on:click={() => {
|
||||
if (selectable) {
|
||||
selectedIndex = index;
|
||||
domTable.focus();
|
||||
}
|
||||
if (clickable) {
|
||||
dispatch('clickrow', row);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#each columnList as col}
|
||||
<td
|
||||
class:isHighlighted={col.isHighlighted && col.isHighlighted(row)}
|
||||
style={col.width ? `width: ${col.width}` : undefined}
|
||||
>
|
||||
{#if col.component}
|
||||
<svelte:component this={col.component} {...col.getProps(row)} />
|
||||
{:else if col.formatter}
|
||||
{col.formatter(row)}
|
||||
{:else if col.slot != null}
|
||||
{#if col.slot == -1}<slot name="-1" {row} {index} />
|
||||
{:else if col.slot == 0}<slot name="0" {row} {index} />
|
||||
{:else if col.slot == 1}<slot name="1" {row} {index} />
|
||||
{:else if col.slot == 2}<slot name="2" {row} {index} />
|
||||
{:else if col.slot == 3}<slot name="3" {row} {index} />
|
||||
{:else if col.slot == 4}<slot name="4" {row} {index} />
|
||||
{:else if col.slot == 5}<slot name="5" {row} {index} />
|
||||
{:else if col.slot == 6}<slot name="6" {row} {index} />
|
||||
{:else if col.slot == 7}<slot name="7" {row} {index} />
|
||||
{/if}
|
||||
{:else}
|
||||
{row[col.fieldName] || ''}
|
||||
{/if}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
table thead,
|
||||
table tbody tr {
|
||||
display: table;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
table thead {
|
||||
width: calc(100% - 0.8em);
|
||||
}
|
||||
table tbody tr td {
|
||||
overflow: hidden;
|
||||
}
|
||||
table tbody {
|
||||
display: block;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
table-layout: fixed;
|
||||
max-height: calc(100% - 20px);
|
||||
}
|
||||
|
||||
table.disableFocusOutline:focus {
|
||||
outline: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
table.selectable {
|
||||
user-select: none;
|
||||
}
|
||||
tbody tr {
|
||||
background: var(--theme-bg-0);
|
||||
}
|
||||
tbody tr.selected {
|
||||
background: var(--theme-bg-selected);
|
||||
}
|
||||
tbody tr.clickable:hover {
|
||||
background: var(--theme-bg-hover);
|
||||
}
|
||||
|
||||
thead td {
|
||||
border: 1px solid var(--theme-border);
|
||||
background-color: var(--theme-bg-1);
|
||||
padding: 5px;
|
||||
}
|
||||
tbody td {
|
||||
border: 1px solid var(--theme-border);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
td.isHighlighted {
|
||||
background-color: var(--theme-bg-1);
|
||||
}
|
||||
</style>
|
@ -25,7 +25,7 @@
|
||||
export let clickable = false;
|
||||
export let disableFocusOutline = false;
|
||||
|
||||
export let domTable;
|
||||
export let domTable = undefined;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
import _ from 'lodash';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import ScrollableTableControl from '../elements/ScrollableTableControl.svelte';
|
||||
import TabControl from '../elements/TabControl.svelte';
|
||||
import TableControl from '../elements/TableControl.svelte';
|
||||
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
|
||||
@ -116,16 +117,16 @@
|
||||
</FormProviderCore>
|
||||
|
||||
<div class="tableWrapper">
|
||||
<TableControl
|
||||
<ScrollableTableControl
|
||||
rows={diffRows}
|
||||
bind:selectedIndex={pairIndex}
|
||||
selectable
|
||||
disableFocusOutline
|
||||
columns={[
|
||||
{ fieldName: 'type', header: 'Type' },
|
||||
{ fieldName: 'type', header: 'Type', width: '100px' },
|
||||
{ fieldName: 'sourceSchemaName', header: 'Schema' },
|
||||
{ fieldName: 'sourcePureName', header: 'Name' },
|
||||
{ fieldName: 'state', header: 'Action' },
|
||||
{ fieldName: 'state', header: 'Action', width: '100px' },
|
||||
{ fieldName: 'targetSchemaName', header: 'Schema' },
|
||||
{ fieldName: 'targetPureName', header: 'Name' },
|
||||
]}
|
||||
@ -179,7 +180,7 @@
|
||||
}
|
||||
|
||||
.tableWrapper {
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user