wip on virtuallist

This commit is contained in:
Philipp Dormann 2021-04-06 22:16:24 +02:00
parent 5cc4871ec4
commit 6304116edb
4 changed files with 165 additions and 117 deletions

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"svelteSortOrder": "options-styles-scripts-markup",
"svelteStrictMode": true,
"svelteBracketNewLine": false,
"svelteAllowShorthand": false,
"svelteIndentScriptAndStyle": false
}

View File

@ -1,14 +0,0 @@
{
"recommendations": [
"2gua.rainbow-brackets",
"christian-kohler.npm-intellisense",
"remimarsal.prettier-now",
"svelte.svelte-vscode",
"lokalise.i18n-ally",
"fivethree.vscode-svelte-snippets",
"voorjaar.windicss-intellisense"
],
"unwantedRecommendations": [
"antfu.i18n-ally"
]
}

View File

@ -10,13 +10,13 @@
}, },
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"devDependencies": { "devDependencies": {
"check-password-strength": "2.0.2",
"@odit/lfk-client-js": "0.10.1", "@odit/lfk-client-js": "0.10.1",
"@odit/license-exporter": "0.0.11", "@odit/license-exporter": "0.0.11",
"@sveltejs/vite-plugin-svelte": "1.0.0-next.5", "@sveltejs/vite-plugin-svelte": "1.0.0-next.5",
"@types/html-minifier": "4.0.0", "@types/html-minifier": "4.0.0",
"auto-changelog": "2.2.1", "auto-changelog": "2.2.1",
"autoprefixer": "10.2.5", "autoprefixer": "10.2.5",
"check-password-strength": "2.0.2",
"csvtojson": "2.0.10", "csvtojson": "2.0.10",
"gridjs": "3.4.0", "gridjs": "3.4.0",
"html-minifier": "4.0.0", "html-minifier": "4.0.0",
@ -28,6 +28,7 @@
"svelte-i18n": "3.3.9", "svelte-i18n": "3.3.9",
"svelte-preprocess": "4.7.0", "svelte-preprocess": "4.7.0",
"svelte-select": "3.17.0", "svelte-select": "3.17.0",
"svelte-tiny-virtual-list": "^1.1.5",
"tailwindcss": "2.0.4", "tailwindcss": "2.0.4",
"tinro": "0.6.1", "tinro": "0.6.1",
"toastify-js": "1.10.0", "toastify-js": "1.10.0",
@ -52,5 +53,8 @@
"hooks": { "hooks": {
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add index.html && node order.js && git add src/locales" "after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add index.html && node order.js && git add src/locales"
} }
},
"dependencies": {
"svelte-infinite-loading": "^1.3.6"
} }
} }

View File

@ -1,5 +1,6 @@
<script> <script>
import { getLocaleFromNavigator, json, _ } from "svelte-i18n"; import { getLocaleFromNavigator, json, _ } from "svelte-i18n";
import InfiniteLoading from 'svelte-infinite-loading';
import { RunnerCardService } from "@odit/lfk-client-js"; import { RunnerCardService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
@ -11,11 +12,20 @@
export let editable = {}; export let editable = {};
export let original_data = {}; export let original_data = {};
export let current_cards = []; export let current_cards = [];
$: filtered_cards = current_cards.filter(function (c) {
if (
c.code.toLowerCase().includes(searchvalue.toLowerCase()) ||
c.runner?.firstname.toLowerCase().includes(searchvalue.toLowerCase()) ||
c.runner?.middlename.toLowerCase().includes(searchvalue.toLowerCase()) ||
c.runner?.lastname.toLowerCase().includes(searchvalue.toLowerCase()) ||
should_display_based_on_id(c.id)
) {
return true;
}
});
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: cards_show = current_cards.some( $: cards_show = current_cards.some((r) => r.is_selected === true);
(r) => r.is_selected === true
);
$: generate_cards = current_cards.filter((r) => r.is_selected === true); $: generate_cards = current_cards.filter((r) => r.is_selected === true);
const cards_promise = RunnerCardService.runnerCardControllerGetAll().then( const cards_promise = RunnerCardService.runnerCardControllerGetAll().then(
(val) => { (val) => {
@ -46,8 +56,39 @@
original_data = Object.assign(original_data, card); original_data = Object.assign(original_data, card);
edit_modal_open = true; edit_modal_open = true;
} }
// -----------------
export let wrapperHeight = "500px";
export let wrapperWidth = "1000px";
let scrollTop = 0;
$: rendered = filtered_cards;
let innerHeight = 0;
let ele;
$: updateSlice(scrollTop);
$: innerHeight = `${filtered_cards.length * 25}px`;
$: if (ele) updateSlice();
function updateSlice() {
const height = ele ? parseInt(ele.clientHeight) : 100;
const init = scrollTop / 25;
const end = Math.ceil((scrollTop + height) / 25);
rendered = filtered_cards.slice(init, end + 15);
}
function updateScroll($event) {
scrollTop = $event.target.scrollTop;
}
</script> </script>
<style>
.virtual-wrapper {
overflow-y: scroll;
margin: 0 auto;
}
.inner-wrapper {
overflow: hidden;
position: relative;
width: 100%;
}
</style>
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:UPDATE')} {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:UPDATE')}
<CardDetailModal <CardDetailModal
bind:current_cards bind:current_cards
@ -80,6 +121,7 @@
bind:cards_show bind:cards_show
bind:generate_cards /> bind:generate_cards />
</div> </div>
{rendered.length}
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
<table class="divide-y divide-gray-200 w-full"> <table class="divide-y divide-gray-200 w-full">
@ -122,106 +164,115 @@
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-200"> <tbody class="divide-y divide-gray-200">
{#each current_cards as card} <!-- //// -->
{#if card.code <div
.toLowerCase() class="virtual-wrapper"
.includes( on:scroll={updateScroll}
searchvalue.toLowerCase() style="height: {wrapperHeight}; width: {wrapperWidth}"
) || card.runner?.firstname bind:this={ele}>
.toLowerCase() <div class="inner-wrapper" style="height: {innerHeight}">
.includes( {#each filtered_cards as card, index}
searchvalue.toLowerCase() {#if card.code
) || card.runner?.middlename .toLowerCase()
.toLowerCase() .includes(
.includes( searchvalue.toLowerCase()
searchvalue.toLowerCase() ) || card.runner?.firstname
) || card.runner?.lastname .toLowerCase()
.toLowerCase() .includes(
.includes( searchvalue.toLowerCase()
searchvalue.toLowerCase() ) || card.runner?.middlename
) || should_display_based_on_id(card.id)} .toLowerCase()
<tr data-rowid="card_{card.id}"> .includes(
<td class="px-6 py-4 whitespace-nowrap"> searchvalue.toLowerCase()
<input ) || card.runner?.lastname
bind:checked={card.is_selected} .toLowerCase()
type="checkbox" .includes(
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> searchvalue.toLowerCase()
</td> ) || should_display_based_on_id(card.id)}
<td class="px-6 py-4 whitespace-nowrap"> <tr data-rowid="card_{card.id}">
<div class="flex items-center">{card.code}</div> <td class="px-6 py-4 whitespace-nowrap">
</td> <input
<td class="px-6 py-4 whitespace-nowrap"> bind:checked={card.is_selected}
<div class="flex items-center"> type="checkbox"
{#if card.runner} class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
<a </td>
href="../runners/{card.runner.id}" <td class="px-6 py-4 whitespace-nowrap">
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{card.runner.firstname} <div class="flex items-center">{card.code}</div>
{card.runner.middlename || ''} </td>
{card.runner.lastname}</a> <td class="px-6 py-4 whitespace-nowrap">
{:else}{$_('non-blanko')}{/if} <div class="flex items-center">
</div> {#if card.runner}
</td> <a
<td class="px-6 py-4 whitespace-nowrap"> href="../runners/{card.runner.id}"
<div class="flex items-center"> class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{card.runner.firstname}
{#if card.enabled} {card.runner.middlename || ''}
<span {card.runner.lastname}</a>
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('enabled')}</span> {:else}{$_('non-blanko')}{/if}
{:else} </div>
<span </td>
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('disabled')}</span> <td class="px-6 py-4 whitespace-nowrap">
{/if} <div class="flex items-center">
</div> {#if card.enabled}
</td> <span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('enabled')}</span>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('disabled')}</span>
{/if}
</div>
</td>
{#if active_deletes[card.id] === true} {#if active_deletes[card.id] === true}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button <button
on:click={() => { on:click={() => {
active_deletes[card.id] = false; active_deletes[card.id] = false;
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button <button
on:click={() => { on:click={() => {
RunnerCardService.runnerCardControllerRemove(card.id, false).then( RunnerCardService.runnerCardControllerRemove(card.id, false).then(
(resp) => { (resp) => {
current_cards = current_cards.filter( current_cards = current_cards.filter(
(obj) => obj.id !== card.id (obj) => obj.id !== card.id
); );
Toastify({ Toastify({
text: $_('card-deleted'), text: $_('card-deleted'),
duration: 500, duration: 500,
backgroundColor: backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)', 'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast(); }).showToast();
} }
); );
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
</td> </td>
{:else} {:else}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button <button
on:click={() => { on:click={() => {
open_edit_modal(card); open_edit_modal(card);
}} }}
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</button> class="text-indigo-600 hover:text-indigo-900">{$_('details')}</button>
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:DELETE')} {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:DELETE')}
<button <button
on:click={() => { on:click={() => {
active_deletes[card.id] = true; active_deletes[card.id] = true;
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button>
{/if} {/if}
</td> </td>
{/if} {/if}
</tr> </tr>
{/if} {/if}
{/each} {/each}
</div>
</div>
</tbody> </tbody>
</table> </table>
</div> </div>