mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-21 17:36:01 +00:00
grid scroll bars
This commit is contained in:
@@ -1,15 +1,36 @@
|
||||
<script lang="ts">
|
||||
import FontIcon from '../icons/FontIcon.svelte';
|
||||
import DropDownButton from '../widgets/DropDownButton.svelte';
|
||||
|
||||
import ColumnLabel from './ColumnLabel.svelte';
|
||||
|
||||
export let column;
|
||||
export let conid = undefined;
|
||||
export let database = undefined;
|
||||
export let column;
|
||||
export let grouping = undefined;
|
||||
export let order = undefined;
|
||||
</script>
|
||||
|
||||
<div class="header">
|
||||
<div class="label">
|
||||
{#if grouping}
|
||||
<span class="grouping">
|
||||
{grouping == 'COUNT DISTINCT' ? 'distinct' : grouping.toLowerCase()}
|
||||
</span>
|
||||
{/if}
|
||||
<ColumnLabel {...column} />
|
||||
</div>
|
||||
{#if order == 'ASC'}
|
||||
<span class="icon">
|
||||
<FontIcon icon="img sort-asc" />
|
||||
</span>
|
||||
{/if}
|
||||
{#if order == 'DESC'}
|
||||
<span class="icon">
|
||||
<FontIcon icon="img sort-desc" />
|
||||
</span>
|
||||
{/if}
|
||||
<DropDownButton />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
{value.toString()}
|
||||
{/if}
|
||||
|
||||
{#if hintFieldsAllowed && hintFieldsAllowed.includes(col.uniqueName)}
|
||||
{#if hintFieldsAllowed && hintFieldsAllowed.includes(col.uniqueName) && rowData}
|
||||
<span class="hint">{rowData[col.hintColumnName]}</span>
|
||||
{/if}
|
||||
</td>
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import ColumnHeaderControl from './ColumnHeaderControl.svelte';
|
||||
import DataGridRow from './DataGridRow.svelte';
|
||||
import { countColumnSizes, countVisibleRealColumns } from './gridutil';
|
||||
import HorizontalScrollBar from './HorizontalScrollBar.svelte';
|
||||
import VerticalScrollBar from './VerticalScrollBar.svelte';
|
||||
|
||||
export let loadNextData = undefined;
|
||||
export let grider = undefined;
|
||||
@@ -17,7 +19,7 @@
|
||||
let firstVisibleRowScrollIndex = 0;
|
||||
let firstVisibleColumnScrollIndex = 0;
|
||||
// $: firstVisibleRowScrollIndex = 0;
|
||||
$: visibleRowCountUpperBound = 25;
|
||||
// $: visibleRowCountUpperBound = 25;
|
||||
|
||||
// $: console.log('grider', grider);
|
||||
$: columns = display.allColumns;
|
||||
@@ -29,6 +31,9 @@
|
||||
$: gridScrollAreaHeight = containerHeight - 2 * rowHeight;
|
||||
$: gridScrollAreaWidth = containerWidth - columnSizes.frozenSize - headerColWidth - 32;
|
||||
|
||||
$: visibleRowCountUpperBound = Math.ceil(gridScrollAreaHeight / Math.floor(Math.max(1, rowHeight)));
|
||||
$: visibleRowCountLowerBound = Math.floor(gridScrollAreaHeight / Math.ceil(Math.max(1, rowHeight)));
|
||||
|
||||
$: visibleRealColumns = countVisibleRealColumns(
|
||||
columnSizes,
|
||||
firstVisibleColumnScrollIndex,
|
||||
@@ -36,12 +41,17 @@
|
||||
columns
|
||||
);
|
||||
|
||||
$: console.log('visibleRealColumns', visibleRealColumns);
|
||||
// $: console.log('visibleRealColumns', visibleRealColumns);
|
||||
$: console.log('visibleRowCountUpperBound', visibleRowCountUpperBound);
|
||||
$: console.log('rowHeight', rowHeight);
|
||||
$: console.log('containerHeight', containerHeight);
|
||||
|
||||
$: realColumnUniqueNames = _.range(columnSizes.realCount).map(
|
||||
realIndex => (columns[columnSizes.realToModel(realIndex)] || {}).uniqueName
|
||||
);
|
||||
|
||||
$: maxScrollColumn = columnSizes.scrollInView(0, columns.length - 1 - columnSizes.frozenCount, gridScrollAreaWidth);
|
||||
|
||||
$: {
|
||||
if (loadNextData && firstVisibleRowScrollIndex + visibleRowCountUpperBound >= grider.rowCount) {
|
||||
loadNextData();
|
||||
@@ -54,7 +64,7 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="header-cell" data-row="header" data-col="header" />
|
||||
<td class="header-cell" data-row="header" data-col="header" bind:clientHeight={rowHeight} />
|
||||
{#each visibleRealColumns as col (col.uniqueName)}
|
||||
<td
|
||||
class="header-cell"
|
||||
@@ -69,10 +79,22 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each _.range(firstVisibleRowScrollIndex, firstVisibleRowScrollIndex + visibleRowCountUpperBound) as rowIndex (rowIndex)}
|
||||
<DataGridRow {rowIndex} {grider} {visibleRealColumns} />
|
||||
<DataGridRow {rowIndex} {grider} {visibleRealColumns} {rowHeight} />
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<HorizontalScrollBar
|
||||
minimum={0}
|
||||
maximum={maxScrollColumn}
|
||||
viewportRatio={gridScrollAreaWidth / columnSizes.getVisibleScrollSizeSum()}
|
||||
on:scroll={e => (firstVisibleColumnScrollIndex = e.detail)}
|
||||
/>
|
||||
<VerticalScrollBar
|
||||
minimum={0}
|
||||
maximum={grider.rowCount - visibleRowCountUpperBound + 2}
|
||||
viewportRatio={visibleRowCountUpperBound / grider.rowCount}
|
||||
on:scroll={e => (firstVisibleRowScrollIndex = e.detail)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -98,7 +120,7 @@
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: var(--theme-bg-2);
|
||||
background-color: var(--theme-bg-1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.filter-cell {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
.map(col => col.uniqueName);
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
<tr style={`height: ${rowHeight}px`}>
|
||||
<RowHeaderCell {rowIndex} />
|
||||
{#each visibleRealColumns as col (col.uniqueName)}
|
||||
<DataGridCell {rowIndex} {rowData} {col} {hintFieldsAllowed} />
|
||||
|
||||
35
packages/web/src/datagrid/HorizontalScrollBar.svelte
Normal file
35
packages/web/src/datagrid/HorizontalScrollBar.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
export let viewportRatio = 0.5;
|
||||
export let minimum;
|
||||
export let maximum;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let width;
|
||||
let node;
|
||||
$: contentSize = Math.round(width / viewportRatio);
|
||||
|
||||
function handleScroll() {
|
||||
const position = node.scrollLeft;
|
||||
const ratio = position / (contentSize - width);
|
||||
if (ratio < 0) return 0;
|
||||
const res = ratio * (maximum - minimum + 1) + minimum;
|
||||
dispatch('scroll', Math.floor(res + 0.3));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:clientWidth={width} bind:this={node} on:scroll={handleScroll} class="main">
|
||||
<div style={`width: ${contentSize}px`}> </div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.main {
|
||||
overflow-x: scroll;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
36
packages/web/src/datagrid/VerticalScrollBar.svelte
Normal file
36
packages/web/src/datagrid/VerticalScrollBar.svelte
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
export let viewportRatio = 0.5;
|
||||
export let minimum;
|
||||
export let maximum;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let height;
|
||||
let node;
|
||||
$: contentSize = Math.round(height / viewportRatio);
|
||||
|
||||
function handleScroll() {
|
||||
const position = node.scrollTop;
|
||||
const ratio = position / (contentSize - height);
|
||||
if (ratio < 0) return 0;
|
||||
let res = ratio * (maximum - minimum + 1) + minimum;
|
||||
dispatch('scroll', Math.floor(res + 0.3));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:clientHeight={height} bind:this={node} on:scroll={handleScroll} class="main">
|
||||
<div style={`height: ${contentSize}px`}> </div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.main {
|
||||
overflow-y: scroll;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 20px;
|
||||
bottom: 16px;
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
||||
8
packages/web/src/widgets/DropDownButton.svelte
Normal file
8
packages/web/src/widgets/DropDownButton.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import FontIcon from '../icons/FontIcon.svelte';
|
||||
import InlineButton from './InlineButton.svelte';
|
||||
</script>
|
||||
|
||||
<InlineButton square>
|
||||
<FontIcon icon="icon chevron-down" />
|
||||
</InlineButton>
|
||||
@@ -11,9 +11,12 @@
|
||||
|
||||
<style>
|
||||
.outer {
|
||||
background: linear-gradient(to bottom, var(--theme-bg-2) 5%, var(--theme-bg-3) 100%);
|
||||
background-color: var(--theme-bg-2);
|
||||
border: 1px solid var(--theme-bg-3);
|
||||
--bg-1: var(--theme-bg-1);
|
||||
--bg-2: var(--theme-bg-3);
|
||||
|
||||
background: linear-gradient(to bottom, var(--bg-1) 5%, var(--bg-2) 100%);
|
||||
background-color: var(--bg-1);
|
||||
border: 1px solid var(--bg-2);
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
@@ -30,9 +33,9 @@
|
||||
}
|
||||
|
||||
.outer:hover:not(.disabled) {
|
||||
border: 1px solid var(--theme-bg-2);
|
||||
background: linear-gradient(to bottom, var(--theme-bg-3) 5%, var(--theme-bg-2) 100%);
|
||||
background-color: var(--theme-bg-3);
|
||||
border: 1px solid var(--bg-1);
|
||||
background: linear-gradient(to bottom, var(--bg-2) 5%, var(--bg-1) 100%);
|
||||
background-color: var(--bg-2);
|
||||
}
|
||||
|
||||
.inner {
|
||||
|
||||
Reference in New Issue
Block a user