Browse Source

fix(gui): introduce infinite scroll to avoid delay in loading emoji list

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/4630/head
Pranav C 2 years ago
parent
commit
970b2b3229
  1. 17
      packages/nc-gui/components/dashboard/TreeView.vue
  2. 14
      packages/nc-gui/components/general/EmojiIcons.vue
  3. 7
      packages/nc-gui/components/general/IconifyIcon.vue
  4. 11
      packages/nc-gui/package-lock.json
  5. 1
      packages/nc-gui/package.json
  6. 3
      packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue

17
packages/nc-gui/components/dashboard/TreeView.vue

@ -3,6 +3,7 @@ import type { TableType } from 'nocodb-sdk'
import type { Input } from 'ant-design-vue' import type { Input } from 'ant-design-vue'
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import GithubButton from 'vue-github-button' import GithubButton from 'vue-github-button'
import { Icon } from '@iconify/vue'
import type { VNodeRef } from '#imports' import type { VNodeRef } from '#imports'
import { import {
ClientType, ClientType,
@ -27,7 +28,7 @@ import {
import MdiView from '~icons/mdi/eye-circle-outline' import MdiView from '~icons/mdi/eye-circle-outline'
import MdiTableLarge from '~icons/mdi/table-large' import MdiTableLarge from '~icons/mdi/table-large'
const { addTab , updateTab } = useTabs() const { addTab, updateTab } = useTabs()
const { $api, $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
@ -307,14 +308,12 @@ const setIcon = (icon: string, table: TableType) => {
} }
tables.value.splice(tables.value.indexOf(table), 1, { ...table }) tables.value.splice(tables.value.indexOf(table), 1, { ...table })
updateTab({ id: table.id }, { meta: table.meta }) updateTab({ id: table.id }, { meta: table.meta })
$api.dbTable.update(table.id as string, { $api.dbTable.update(table.id as string, {
meta: table.meta, meta: table.meta,
}) })
} }
</script> </script>
<template> <template>
@ -568,20 +567,16 @@ const setIcon = (icon: string, table: TableType) => {
<div class="flex w-auto" :data-testid="`tree-view-table-draggable-handle-${table.title}`"> <div class="flex w-auto" :data-testid="`tree-view-table-draggable-handle-${table.title}`">
<a-dropdown trigger="click" @click.stop> <a-dropdown trigger="click" @click.stop>
<div @click.stop> <div @click.stop>
<!-- <MdiDrag <!-- <MdiDrag
v-if="isUIAllowed('treeview-drag-n-drop')" v-if="isUIAllowed('treeview-drag-n-drop')"
:class="`nc-child-draggable-icon-${table.title}`" :class="`nc-child-draggable-icon-${table.title}`"
class="nc-drag-icon text-xs hidden group-hover:block transition-opacity opacity-0 group-hover:opacity-100 text-gray-500 cursor-move" class="nc-drag-icon text-xs hidden group-hover:block transition-opacity opacity-0 group-hover:opacity-100 text-gray-500 cursor-move"
@click.stop.prevent @click.stop.prevent
/>--> /> -->
<a-tooltip> <a-tooltip>
<span v-if="table.meta?.icon" :key="table.meta?.icon"> <span v-if="table.meta?.icon" :key="table.meta?.icon">
<GeneralIconifyIcon <Icon :key="table.meta?.icon" class="text-xl" :icon="table.meta?.icon"></Icon>
:key="table.meta?.icon"
class="text-xl"
:icon="table.meta?.icon"
></GeneralIconifyIcon>
</span> </span>
<component <component
:is="icon(table)" :is="icon(table)"
@ -594,7 +589,7 @@ const setIcon = (icon: string, table: TableType) => {
</a-tooltip> </a-tooltip>
</div> </div>
<template #overlay> <template #overlay>
<LazyGeneralEmojiIcons class="shadow bg-white p-2" @select-icon="setIcon($event, table)" /> <GeneralEmojiIcons class="shadow bg-white p-2" @select-icon="setIcon($event, table)" />
</template> </template>
</a-dropdown> </a-dropdown>

14
packages/nc-gui/components/general/EmojiIcons.vue

@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import InfiniteLoading from 'v3-infinite-loading'
const emit = defineEmits(['selectIcon']) const emit = defineEmits(['selectIcon'])
const search = $ref('') const search = $ref('')
@ -1842,15 +1843,23 @@ const icons = [
'zzz', 'zzz',
] ]
let toIndex = $ref(60)
const filteredIcons = computed(() => { const filteredIcons = computed(() => {
return icons.filter((icon) => !search || icon.toLowerCase().includes(search.toLowerCase())) return icons.filter((icon) => !search || icon.toLowerCase().includes(search.toLowerCase())).slice(0, toIndex)
}) })
const load = () => {
toIndex += Math.min(filteredIcons.value.length, toIndex + 60)
if (toIndex > filteredIcons.value.length) {
toIndex = filteredIcons.value.length
}
}
</script> </script>
<template> <template>
<div class="p-1 w-70 h-75 flex flex-col gap-1 justify-start"> <div class="p-1 w-70 h-75 flex flex-col gap-1 justify-start">
<div @click.stop> <div @click.stop>
<input v-model="search" class="p-1 border-1 w-full overflow-y-auto" placeholder="Search" /> <input v-model="search" class="p-1 border-1 w-full overflow-y-auto" placeholder="Search" @input="toIndex = 60" />
</div> </div>
<div class="flex gap-1 flex-wrap w-full flex-shrink overflow-y-auto scrollbar-thin-dull"> <div class="flex gap-1 flex-wrap w-full flex-shrink overflow-y-auto scrollbar-thin-dull">
<div v-for="icon of filteredIcons" :key="icon" @click="emit('selectIcon', `emojione:${icon}`)"> <div v-for="icon of filteredIcons" :key="icon" @click="emit('selectIcon', `emojione:${icon}`)">
@ -1858,6 +1867,7 @@ const filteredIcons = computed(() => {
<Icon class="text-xl iconify" :icon="`emojione:${icon}`"></Icon> <Icon class="text-xl iconify" :icon="`emojione:${icon}`"></Icon>
</span> </span>
</div> </div>
<InfiniteLoading @infinite="load"><span /></InfiniteLoading>
</div> </div>
</div> </div>
</template> </template>

7
packages/nc-gui/components/general/IconifyIcon.vue

@ -1,7 +0,0 @@
<script lang="ts" setup>
import { Icon } from '@iconify/vue'
</script>
<template>
<Icon :icon="icon" />
</template>

11
packages/nc-gui/package-lock.json generated

@ -35,6 +35,7 @@
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"tinycolor2": "^1.4.2", "tinycolor2": "^1.4.2",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"v3-infinite-loading": "^1.2.2",
"validator": "^13.7.0", "validator": "^13.7.0",
"vue-dompurify-html": "^3.0.0", "vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3", "vue-github-button": "^3.0.3",
@ -16190,6 +16191,11 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/v3-infinite-loading": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/v3-infinite-loading/-/v3-infinite-loading-1.2.2.tgz",
"integrity": "sha512-MWJc6yChnqeUasBFJ3Enu8IGPcQgRMSTrAEtT1MsHBEx+QjwvNTaY8o+8V9DgVt1MVhQSl3MC55hsaWLJmpRMw=="
},
"node_modules/v8-compile-cache": { "node_modules/v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
@ -29538,6 +29544,11 @@
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"dev": true "dev": true
}, },
"v3-infinite-loading": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/v3-infinite-loading/-/v3-infinite-loading-1.2.2.tgz",
"integrity": "sha512-MWJc6yChnqeUasBFJ3Enu8IGPcQgRMSTrAEtT1MsHBEx+QjwvNTaY8o+8V9DgVt1MVhQSl3MC55hsaWLJmpRMw=="
},
"v8-compile-cache": { "v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",

1
packages/nc-gui/package.json

@ -58,6 +58,7 @@
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"tinycolor2": "^1.4.2", "tinycolor2": "^1.4.2",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"v3-infinite-loading": "^1.2.2",
"validator": "^13.7.0", "validator": "^13.7.0",
"vue-dompurify-html": "^3.0.0", "vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3", "vue-github-button": "^3.0.3",

3
packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Icon } from '@iconify/vue'
import type { TabItem } from '~/lib' import type { TabItem } from '~/lib'
import { TabType } from '~/lib' import { TabType } from '~/lib'
import { TabMetaInj, iconMap, provide, useGlobal, useSidebar, useTabs } from '#imports' import { TabMetaInj, iconMap, provide, useGlobal, useSidebar, useTabs } from '#imports'
@ -48,7 +49,7 @@ function onEdit(targetKey: number, action: 'add' | 'remove' | string) {
<template #tab> <template #tab>
<div class="flex items-center gap-2 max-w-[110px]"> <div class="flex items-center gap-2 max-w-[110px]">
<div class="flex items-center"> <div class="flex items-center">
<GeneralIconifyIcon v-if="tab.meta?.icon" :icon="tab.meta?.icon" class="text-xl" /> <Icon v-if="tab.meta?.icon" :icon="tab.meta?.icon" class="text-xl" />
<component :is="icon(tab)" v-else class="text-sm" /> <component :is="icon(tab)" v-else class="text-sm" />
</div> </div>

Loading…
Cancel
Save