diff --git a/package-lock.json b/package-lock.json index 591fedf..53e1e16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,10 @@ "@actions/core": "^1.10.0", "@actions/exec": "^1.1.1", "@actions/github": "^5.1.1", + "@crabnebula/tauri-plugin-drag": "^0.3.1", "@prisma/client": "^4.9.0", "@tanstack/solid-table": "^8.10.6", - "@tanstack/solid-virtual": "3.0", + "@tanstack/solid-virtual": "^3.5.1", "@tauri-apps/api": "^1.5.1", "github": "^14.0.0", "howler": "^2.2.3", @@ -529,6 +530,14 @@ "node": ">=0.1.90" } }, + "node_modules/@crabnebula/tauri-plugin-drag": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@crabnebula/tauri-plugin-drag/-/tauri-plugin-drag-0.3.1.tgz", + "integrity": "sha512-GCJhlhzM/cEI5PSxE64pbysg8ghcnRDxXPNtGjCl2AiVFVuMwSrfCOc2BZbd/ALtuctxVjaSfrpScmcz5V4gmA==", + "dependencies": { + "@tauri-apps/api": "^1.5.4" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.11", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", @@ -2073,11 +2082,11 @@ } }, "node_modules/@tanstack/solid-virtual": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@tanstack/solid-virtual/-/solid-virtual-3.0.4.tgz", - "integrity": "sha512-DhRYkJE6P1WjZvtzuLx6/k1CVNY6oESJwO/OGktOOFclYOC0cdXSTNg+lH4f5OPoSXkeFOr4Slbld6RVO9kf+w==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@tanstack/solid-virtual/-/solid-virtual-3.5.1.tgz", + "integrity": "sha512-BhDKs3DDwGvA45rAgqeN3igcV0BJMwUX9lDxPmGDg2jEnGUy/iNeV5a8WexbbmOHzQiPNOZWirRU4C0Zc7nBnA==", "dependencies": { - "@tanstack/virtual-core": "3.0.0" + "@tanstack/virtual-core": "3.5.1" }, "funding": { "type": "github", @@ -2100,18 +2109,18 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz", - "integrity": "sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.5.1.tgz", + "integrity": "sha512-046+AUSiDru/V9pajE1du8WayvBKeCvJ2NmKPy/mR8/SbKKrqmSbj7LJBfXE+nSq4f5TBXvnCzu0kcYebI9WdQ==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tauri-apps/api": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.1.tgz", - "integrity": "sha512-6unsZDOdlXTmauU3NhWhn+Cx0rODV+rvNvTdvolE5Kls5ybA6cqndQENDt1+FS0tF7ozCP66jwWoH6a5h90BrA==", + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.6.tgz", + "integrity": "sha512-LH5ToovAHnDVe5Qa9f/+jW28I6DeMhos8bNDtBOmmnaDpPmJmYLyHdeDblAWWWYc7KKRDg9/66vMuKyq0WIeFA==", "engines": { "node": ">= 14.6.0", "npm": ">= 6.6.0", @@ -12201,6 +12210,14 @@ "dev": true, "optional": true }, + "@crabnebula/tauri-plugin-drag": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@crabnebula/tauri-plugin-drag/-/tauri-plugin-drag-0.3.1.tgz", + "integrity": "sha512-GCJhlhzM/cEI5PSxE64pbysg8ghcnRDxXPNtGjCl2AiVFVuMwSrfCOc2BZbd/ALtuctxVjaSfrpScmcz5V4gmA==", + "requires": { + "@tauri-apps/api": "^1.5.4" + } + }, "@esbuild/aix-ppc64": { "version": "0.19.11", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", @@ -13188,11 +13205,11 @@ } }, "@tanstack/solid-virtual": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@tanstack/solid-virtual/-/solid-virtual-3.0.4.tgz", - "integrity": "sha512-DhRYkJE6P1WjZvtzuLx6/k1CVNY6oESJwO/OGktOOFclYOC0cdXSTNg+lH4f5OPoSXkeFOr4Slbld6RVO9kf+w==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@tanstack/solid-virtual/-/solid-virtual-3.5.1.tgz", + "integrity": "sha512-BhDKs3DDwGvA45rAgqeN3igcV0BJMwUX9lDxPmGDg2jEnGUy/iNeV5a8WexbbmOHzQiPNOZWirRU4C0Zc7nBnA==", "requires": { - "@tanstack/virtual-core": "3.0.0" + "@tanstack/virtual-core": "3.5.1" } }, "@tanstack/table-core": { @@ -13201,14 +13218,14 @@ "integrity": "sha512-9t8brthhAmCBIjzk7fCDa/kPKoLQTtA31l9Ir76jYxciTlHU61r/6gYm69XF9cbg9n88gVL5y7rNpeJ2dc1AFA==" }, "@tanstack/virtual-core": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.0.0.tgz", - "integrity": "sha512-SYXOBTjJb05rXa2vl55TTwO40A6wKu0R5i1qQwhJYNDIqaIGF7D0HsLw+pJAyi2OvntlEIVusx3xtbbgSUi6zg==" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.5.1.tgz", + "integrity": "sha512-046+AUSiDru/V9pajE1du8WayvBKeCvJ2NmKPy/mR8/SbKKrqmSbj7LJBfXE+nSq4f5TBXvnCzu0kcYebI9WdQ==" }, "@tauri-apps/api": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.1.tgz", - "integrity": "sha512-6unsZDOdlXTmauU3NhWhn+Cx0rODV+rvNvTdvolE5Kls5ybA6cqndQENDt1+FS0tF7ozCP66jwWoH6a5h90BrA==" + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.6.tgz", + "integrity": "sha512-LH5ToovAHnDVe5Qa9f/+jW28I6DeMhos8bNDtBOmmnaDpPmJmYLyHdeDblAWWWYc7KKRDg9/66vMuKyq0WIeFA==" }, "@tauri-apps/cli": { "version": "1.5.6", diff --git a/package.json b/package.json index b4ceaa6..9ff7ff0 100644 --- a/package.json +++ b/package.json @@ -39,17 +39,18 @@ "prisma": "^4.9.0", "semantic-release": "^24.0.0", "tailwindcss": "^3.4.1", - "typescript": "^5", + "typescript": "^5.4.5", "vite": "^5.0.11", "vite-plugin-solid": "^2.10.2" }, "dependencies": { - "@actions/core": "^1.10.0", + "@actions/core": "^1.10.1", "@actions/exec": "^1.1.1", "@actions/github": "^5.1.1", + "@crabnebula/tauri-plugin-drag": "^0.3.1", "@prisma/client": "^4.9.0", "@tanstack/solid-table": "^8.10.6", - "@tanstack/solid-virtual": "3.0", + "@tanstack/solid-virtual": "^3.5.1", "@tauri-apps/api": "^1.5.1", "github": "^14.0.0", "howler": "^2.2.3", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 4b57842..527e8fe 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -730,9 +730,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -740,9 +740,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" @@ -759,13 +759,12 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", - "foreign-types", "libc", ] diff --git a/src/components/FilesTable/FilesTable.tsx b/src/components/FilesTable/FilesTable.tsx index 7d91488..6e2c115 100644 --- a/src/components/FilesTable/FilesTable.tsx +++ b/src/components/FilesTable/FilesTable.tsx @@ -1,6 +1,7 @@ import { filesTableColumns } from "@/components/FilesTable/columns"; import { useSearch } from "@/providers/SearchProvider/SearchProvider"; import { + ColumnSizingState, createSolidTable, flexRender, getCoreRowModel, @@ -17,7 +18,6 @@ import { } from "solid-js"; import { onKeyStroke, useScroll, useStorage } from "solidjs-use"; import { removeSubstrings } from "../../services/helpers/helpers"; -import { OVERSCAN } from "./constants"; import TableRow from "./core/TableRow/TableRow"; import useFilesLoader from "./hooks/useFilesLoader"; import useUpdateSkip from "./hooks/useUpdateSkip"; @@ -25,37 +25,30 @@ import useUpdateSkip from "./hooks/useUpdateSkip"; const FilesTable: Component = () => { const [store, actions] = useSearch(); - const filteredStartsWith = createMemo(() => { + const pathsFiltered = createMemo(() => { return removeSubstrings(store.collapsed); }); const { files, metadataFiles, handleSkipUpdate } = useFilesLoader( - filteredStartsWith, + pathsFiltered, () => store.search ); - const [bodyTableRef, setBodyTableRef] = createSignal(); - const [headerTableRef, setHeaderTableRef] = createSignal(); + let bodyTableRef!: HTMLDivElement; + let headerTableRef!: HTMLDivElement; - const [getColumnsSize, setColumnsSize] = useStorage("columns-size", { - name: 350, - bpm: 150, - simpleRate: 150, - bitDepth: 150, - channels: 150, - duration: 150, - show: 100, - }); - - // const [getColumnsVisible, setColumnsVisible] = useStorage("columns-visible", { - // name: true, - // bpm: true, - // simpleRate: true, - // bitDepth: true, - // channels: true, - // duration: true, - // show: true, - // }); + const [getColumnsSize, setColumnsSize] = useStorage( + "columns-size", + { + name: 350, + bpm: 150, + simpleRate: 150, + bitDepth: 150, + channels: 150, + duration: 150, + show: 100, + } + ); const table = createSolidTable({ get data() { @@ -83,17 +76,18 @@ const FilesTable: Component = () => { ); const rowVirtualizer = createVirtualizer({ - getScrollElement: () => bodyTableRef() ?? null, + getScrollElement: () => bodyTableRef, get count() { return metadataFiles()?.total_count ?? 0; }, - overscan: OVERSCAN, + overscan: 8, estimateSize: () => 45, isScrollingResetDelay: 0, }); useUpdateSkip({ - rowVirtualizer, + getVirtualItems: rowVirtualizer.getVirtualItems, + overscan: rowVirtualizer.options.overscan, enabled: () => !files.loading && !metadataFiles.loading, handleSkipUpdate, isItemLoaded: (index) => { @@ -108,7 +102,7 @@ const FilesTable: Component = () => { const targetElement = event.target as HTMLElement; (targetElement.nextElementSibling as HTMLElement)?.focus(); }, - { target: bodyTableRef } + { target: () => bodyTableRef } ); onKeyStroke( @@ -118,12 +112,12 @@ const FilesTable: Component = () => { const targetElement = event.target as HTMLElement; (targetElement.previousElementSibling as HTMLElement)?.focus(); }, - { target: bodyTableRef } + { target: () => bodyTableRef } ); - const { setX: setXBody, x: xBody } = useScroll(bodyTableRef); + const { setX: setXBody, x: xBody } = useScroll(() => bodyTableRef); - const { setX: setXHeader, x: xHeader } = useScroll(headerTableRef); + const { setX: setXHeader, x: xHeader } = useScroll(() => headerTableRef); createEffect(() => { setXHeader(xBody()); @@ -134,15 +128,18 @@ const FilesTable: Component = () => { }); const handleRandomPosition = async () => { - const totalCount = metadataFiles()?.total_count - 1 ?? 0; - const countRandom = random(0, totalCount); + const totalCount = metadataFiles()?.total_count ?? 0; + const countRandom = random(0, totalCount - 1); setRandomPosition(countRandom); }; createEffect(() => { const randomPosition = getRandomPosition(); if (randomPosition !== null) { - rowVirtualizer.scrollToIndex(randomPosition, { align: "start" }); + rowVirtualizer.scrollToIndex(randomPosition, { + align: "start", + behavior: "auto", + }); if (!files.loading) { const file = files()?.[randomPosition]; if (file?.path) { @@ -155,7 +152,7 @@ const FilesTable: Component = () => { createEffect( on( - [filteredStartsWith, () => store.search], + [pathsFiltered, () => store.search], () => { rowVirtualizer.scrollToOffset(0, { align: "start", @@ -204,8 +201,8 @@ const FilesTable: Component = () => {
{(headerGroup) => ( @@ -238,7 +235,7 @@ const FilesTable: Component = () => {
{ @@ -15,24 +22,33 @@ const getCurrentSkipItems = (index: number): number => { return Math.max(0, calculatedIndex); }; -function useFilesLoader(filteredStartsWith, search) { +interface IFilesLoaderResult { + files: Resource; + metadataFiles: Resource; + handleSkipUpdate: (value: number) => number; +} + +const useFilesLoader: ( + paths: Accessor, + search: Accessor +) => IFilesLoaderResult = (paths, search) => { const [skip, setSkip] = createSignal(0); const [metadataFiles] = createResource< MetadataFiles, FetchMetadataFilesKeys, boolean - >(() => [filteredStartsWith(), search()], getMetadataFiles); + >(() => [paths(), search()], getMetadataFiles); const [files, { mutate: mutateFiles }] = createResource< PrismaFile[], FetchDirectoryFilesKeys, boolean - >(() => [filteredStartsWith(), search(), skip()], getDirectoryFiles); + >(() => [paths(), search(), skip()], getDirectoryFiles); createEffect( on( - [filteredStartsWith, search], + [paths, search], () => { mutateFiles([]); setSkip(0); @@ -48,6 +64,6 @@ function useFilesLoader(filteredStartsWith, search) { return setSkip(getCurrentSkipItems(value || 0)); }, }; -} +}; export default useFilesLoader; diff --git a/src/components/FilesTable/hooks/useUpdateSkip.ts b/src/components/FilesTable/hooks/useUpdateSkip.ts index 42370e5..8b3a0c5 100644 --- a/src/components/FilesTable/hooks/useUpdateSkip.ts +++ b/src/components/FilesTable/hooks/useUpdateSkip.ts @@ -1,20 +1,19 @@ -import { Virtualizer } from "@tanstack/solid-virtual"; +import { VirtualItem } from "@tanstack/solid-virtual"; import { first, last } from "lodash-es"; -import { Component, createEffect } from "solid-js"; +import { createEffect } from "solid-js"; interface UseUpdateSkipProps { enabled: () => boolean; - rowVirtualizer: Virtualizer; + getVirtualItems: () => VirtualItem[]; + overscan: number; isItemLoaded: (index: number) => boolean; handleSkipUpdate: (skip: number) => void; } -export const useUpdateSkip: Component = (props) => { +export const useUpdateSkip: (props: UseUpdateSkipProps) => void = (props) => { createEffect(() => { if (props.enabled()) { - const { overscan } = props.rowVirtualizer.options; - - const virtualItems = props.rowVirtualizer.getVirtualItems(); + const virtualItems = props.getVirtualItems(); const firstIndex = first(virtualItems)?.index; const lastIndex = last(virtualItems)?.index; @@ -22,17 +21,16 @@ export const useUpdateSkip: Component = (props) => { const firstItemLoaded = props.isItemLoaded(firstIndex); const lastItemLoaded = props.isItemLoaded(lastIndex); const firstItemWithOverscanLoaded = props.isItemLoaded( - firstIndex + overscan + firstIndex + props.overscan ); const lastItemWithOverscanLoaded = props.isItemLoaded( - lastIndex - overscan + lastIndex - props.overscan ); - // Mettre des callback props.handleSkipUpdate if (!firstItemWithOverscanLoaded) { - props.handleSkipUpdate(firstIndex + overscan); + props.handleSkipUpdate(firstIndex + props.overscan); } else if (!lastItemWithOverscanLoaded) { - props.handleSkipUpdate(lastIndex - overscan); + props.handleSkipUpdate(lastIndex - props.overscan); } else if (!firstItemLoaded) { props.handleSkipUpdate(firstIndex); } else if (!lastItemLoaded) { diff --git a/src/index.css b/src/index.css index 61c5824..d65945a 100644 --- a/src/index.css +++ b/src/index.css @@ -78,6 +78,15 @@ body { padding: 0 2.5px; } +.hidden-scrollbar { + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE et Edge */ +} + +.hidden-scrollbar::-webkit-scrollbar { + display: none; /* WebKit */ +} + .div-table { @apply text-left text-sm;