From 93dcb3916f8042ca3f97566502eb40b47e53b762 Mon Sep 17 00:00:00 2001 From: alsaze Date: Tue, 18 Nov 2025 15:11:55 +0300 Subject: [PATCH] init --- api/queries/useGetUsers.ts | 2 +- package.json | 3 +- pages/index.vue | 202 +++++++++++++++++++++++++------------ 3 files changed, 138 insertions(+), 69 deletions(-) diff --git a/api/queries/useGetUsers.ts b/api/queries/useGetUsers.ts index 9a4c301..8e9d616 100644 --- a/api/queries/useGetUsers.ts +++ b/api/queries/useGetUsers.ts @@ -4,7 +4,7 @@ import { getUsers } from '~/api/endpoints' export const useGetUsers = () => { return useQuery({ queryKey: ['get-users'], - queryFn: getUsers, + queryFn: () => getUsers(), staleTime: Infinity, }) } diff --git a/package.json b/package.json index c81886f..c48ffb6 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,9 @@ "@nuxt/ui": "^4.0.1", "@nuxtjs/i18n": "^10.0.4", "@tanstack/vue-query": "^5.75.5", - "@tanstack/vue-table": "^8.21.3", "@tanstack/vue-query-devtools": "^5.87.1", + "@tanstack/vue-table": "^8.21.3", + "@tanstack/vue-virtual": "^3.13.12", "@vee-validate/nuxt": "^4.15.1", "@vueuse/core": "^13.1.0", "axios": "^1.12.2", diff --git a/pages/index.vue b/pages/index.vue index 12ab7ef..52e0b3c 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -11,49 +11,58 @@ /> -
- - - - + + +
+
+ + + + - + - - + {{ { asc: ' 🔼', desc: ' 🔽' }[header.column.getIsSorted() as string] }} + + + - - - - - - - -
+ - {{ { asc: ' 🔼', desc: ' 🔽' }[header.column.getIsSorted() as string] }} -
+
+
+ +
+
@@ -81,6 +90,7 @@ import { getSortedRowModel, useVueTable, } from '@tanstack/vue-table' +import { useVirtualizer } from '@tanstack/vue-virtual' import { useDebounceFn, useMediaQuery } from '@vueuse/core' import { useGetPosts, useGetUsers } from '~/api/queries' @@ -108,7 +118,14 @@ const columns = [ columnHelper.accessor('id', { header: 'ID', footer: props => props?.column?.id, - meta: { style: 'text-align: center' }, + meta: { + style: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + }, + size: 50, }), columnHelper.accessor('title', { header: 'Заголовок', @@ -119,15 +136,25 @@ const columns = [ default: () => h('span', { class: 'ellipsis' }, truncate(info.getValue()), ), }), + size: 150, }), columnHelper.accessor('userEmail', { header: 'Автор', - cell: info => h( - 'span', - { class: 'title-cell', onClick: () => openPost(info.row.original) }, - info.getValue(), - ), - meta: { style: 'text-align: center' }, + cell: info => isMobile.value + ? info.getValue() + : h(UTooltip, { text: info.getValue(), + }, { + default: () => h('div', { class: 'title-cell', onClick: () => openPost(info?.row?.original) }, truncate(info.getValue()), + ), + }), + meta: { + style: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + }, + size: 170, }), columnHelper.accessor('body', { header: 'Контент', @@ -136,8 +163,9 @@ const columns = [ : h(UTooltip, { text: info.getValue(), }, { - default: () => h('span', { class: 'ellipsis' }, truncate(info.getValue())), + default: () => h('span', { class: 'ellipsis' }, truncate(info.getValue(), 22)), }), + size: 220, }), ] @@ -150,17 +178,46 @@ const table = useVueTable({ getSortedRowModel: getSortedRowModel(), }) +// The virtualizer needs to know the scrollable container element +const rows = computed(() => table?.getRowModel()?.rows) +const tableContainerRef = ref(null) + +const rowVirtualizerOptions = computed(() => { + return { + count: rows.value.length, + estimateSize: () => 50, // estimate row height for accurate scrollbar dragging + getScrollElement: () => tableContainerRef.value, + overscan: 5, + } +}) + +const rowVirtualizer = useVirtualizer(rowVirtualizerOptions) + +const virtualRows = computed(() => rowVirtualizer.value.getVirtualItems()) +const totalSize = computed(() => rowVirtualizer.value.getTotalSize()) + +function measureElement(el?: Element) { + if (!el) { + return + } + + rowVirtualizer.value.measureElement(el) + + return undefined +} +// virtualizer end + function openPost(post: Post) { selectedUser.value = users?.value?.find(user => user?.id === post?.userId) open.value = true } function truncate(text: string, max = 15) { - return text.length > max ? `${text.slice(0, max)}…` : text + return text?.length > max ? `${text?.slice(0, max)}…` : text } -