From 71c98255a118d967a52fc3bed3c983d216544d1a Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Sun, 17 Mar 2024 15:12:50 +0100 Subject: [PATCH] feat: Instance card dragging --- package.json | 1 + pnpm-lock.yaml | 12 +++++ src/ui/components/Navbar.tsx | 2 +- src/ui/pages/Browser.tsx | 86 +++++++++++++++++++++++++++++++++-- src/ui/pages/Home.tsx | 87 +++++++++++++++++++++++++++++------- 5 files changed, 167 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 4506c4c4..16f9deb3 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@solidjs/router": "^0.13.0", "@tauri-apps/api": "2.0.0-beta.5", "@tauri-apps/plugin-shell": "2.0.0-beta.2", + "@thisbeyond/solid-dnd": "^0.7.5", "@untitled-theme/icons-solid": "^0.6.0", "overlayscrollbars": "^2.6.1", "overlayscrollbars-solid": "^0.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b820fa91..aed5b2b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: '@tauri-apps/plugin-shell': specifier: 2.0.0-beta.2 version: 2.0.0-beta.2 + '@thisbeyond/solid-dnd': + specifier: ^0.7.5 + version: 0.7.5(solid-js@1.8.15) '@untitled-theme/icons-solid': specifier: ^0.6.0 version: 0.6.0(solid-js@1.8.15) @@ -1113,6 +1116,15 @@ packages: '@tauri-apps/api': 2.0.0-beta.4 dev: false + /@thisbeyond/solid-dnd@0.7.5(solid-js@1.8.15): + resolution: {integrity: sha512-DfI5ff+yYGpK9M21LhYwIPlbP2msKxN2ARwuu6GF8tT1GgNVDTI8VCQvH4TJFoVApP9d44izmAcTh/iTCH2UUw==} + engines: {node: '>=18.0.0', pnpm: '>=8.6.0'} + peerDependencies: + solid-js: ^1.5 + dependencies: + solid-js: 1.8.15 + dev: false + /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: diff --git a/src/ui/components/Navbar.tsx b/src/ui/components/Navbar.tsx index 8cdff898..9c016c74 100644 --- a/src/ui/components/Navbar.tsx +++ b/src/ui/components/Navbar.tsx @@ -1,6 +1,6 @@ import { A } from '@solidjs/router'; import { createSignal } from 'solid-js'; -import { Bell01Icon, Cloud01Icon, Settings01Icon, TerminalBrowserIcon, TerminalIcon } from '@untitled-theme/icons-solid'; +import { Bell01Icon, Cloud01Icon, Settings01Icon, TerminalBrowserIcon } from '@untitled-theme/icons-solid'; import useAccount from '../hooks/useAccount'; import PolyfrostFull from './logos/PolyfrostFull'; import AccountPopup from './overlay/AccountPopup'; diff --git a/src/ui/pages/Browser.tsx b/src/ui/pages/Browser.tsx index cc1d670f..f7c44e03 100644 --- a/src/ui/pages/Browser.tsx +++ b/src/ui/pages/Browser.tsx @@ -1,8 +1,88 @@ +import type { DragEventHandler, Id } from '@thisbeyond/solid-dnd'; +import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter, createSortable, useDragDropContext } from '@thisbeyond/solid-dnd'; +import type { JSX } from 'solid-js'; +import { For, createSignal } from 'solid-js'; + +declare module 'solid-js' { + // eslint-disable-next-line ts/no-namespace + namespace JSX { + interface Directives { + sortable: any; + } + } +} + +interface ItemProps { + item: boolean | Id | Node | JSX.ArrayElement | null | undefined; +}; + +function Item(props: ItemProps) { + const id = () => props.item as Id; + // eslint-disable-next-line solid/reactivity + const sortable = createSortable(id()); + + // @ts-expect-error - `state` is not defined in the type definition + const [state] = useDragDropContext(); + + return ( +
+ {props.item} +
+ ); +} + +function List() { + const [items, setItems] = createSignal([1, 2, 3]); + const [activeItem, setActiveItem] = createSignal(null); + const ids = () => items(); + + const onDragStart: DragEventHandler = ({ draggable }) => setActiveItem(draggable.id as number); + + const onDragEnd: DragEventHandler = ({ draggable, droppable }) => { + if (draggable && droppable) { + const currentItems = ids(); + const fromIndex = currentItems.indexOf(draggable.id as number); + const toIndex = currentItems.indexOf(droppable.id as number); + if (fromIndex !== toIndex) { + const updatedItems = currentItems.slice(); + updatedItems.splice(toIndex, 0, ...updatedItems.splice(fromIndex, 1)); + setItems(updatedItems); + } + } + }; + + return ( + + +
+ + {item => } + +
+ +
{activeItem()}
+
+
+ ); +} + function BrowserPage() { return ( -

- Browser -

+
+

Browser

+ +
); } diff --git a/src/ui/pages/Home.tsx b/src/ui/pages/Home.tsx index 0d66834c..2a844ae2 100644 --- a/src/ui/pages/Home.tsx +++ b/src/ui/pages/Home.tsx @@ -6,7 +6,9 @@ import { PlusIcon, SearchMdIcon, } from '@untitled-theme/icons-solid'; -import { For, createEffect, createSignal } from 'solid-js'; +import { For, createSignal } from 'solid-js'; +import { DragDropProvider, DragDropSensors, DragOverlay, SortableProvider, closestCenter, createSortable, useDragDropContext } from '@thisbeyond/solid-dnd'; +import type { DragEventHandler, Id } from '@thisbeyond/solid-dnd'; import image from '../../assets/images/header.png'; import Button from '../components/base/Button'; import Tag from '../components/base/Tag'; @@ -61,14 +63,28 @@ interface InstanceCardProps { name: string; version: string; client: game.Client; + id: number; mods?: number; cover?: string; lastPlayed?: number; } +declare module 'solid-js' { + // eslint-disable-next-line ts/no-namespace + namespace JSX { + interface Directives { + sortable: any; + } + } +} + function InstanceCard(props: InstanceCardProps) { + const id = () => props.id as Id; + // eslint-disable-next-line solid/reactivity + const sortable = createSortable(id()); + return ( -
+
([]); + // eslint-disable-next-line solid/reactivity + const [instances, setInstances] = createSignal(props.instances); + const ids = () => instances().map(instance => instance.id); - createEffect(() => { - setSorted(props.instances.sort((a, b) => { - if (a.lastPlayed && b.lastPlayed) - return b.lastPlayed - a.lastPlayed; + const onDragStart: DragEventHandler = ({ draggable }) => { + draggable.node.style.zIndex = '1000'; + }; - return 0; - })); - }); + const onDragEnd: DragEventHandler = ({ draggable, droppable }) => { + draggable.node.style.zIndex = ''; + if (draggable && droppable) { + const currentItems = ids(); + const fromIndex = currentItems.indexOf(draggable.id as number); + const toIndex = currentItems.indexOf(droppable.id as number); + + if (fromIndex !== toIndex) { + const updatedItems = instances().slice(); + updatedItems.splice(toIndex, 0, ...updatedItems.splice(fromIndex, 1)); + setInstances(updatedItems); + } + } + }; return (

{props.title}

-
- - {instance => ( - - )} - -
+ + +
+ + {item => } + +
+
); } @@ -136,41 +169,61 @@ function HomePage() { name: 'Hypixel', client: 'vanilla', version: '1.8.9', + id: 1, }, { name: 'OneConfig ??', client: 'forge', version: '1.8.9', mods: 12, + id: 2, }, { name: 'Fabulously Optimised', client: 'fabric', version: '1.20.4', mods: 48, + id: 3, }, { name: 'sus client', client: 'other', version: '1.8.9', + id: 4, + }, + { + name: 'Hypixel', + client: 'vanilla', + version: '1.8.9', + id: 5, }, { name: 'OneConfig ??', client: 'forge', version: '1.8.9', mods: 12, + id: 6, }, { name: 'Fabulously Optimised', client: 'fabric', version: '1.20.4', mods: 48, + id: 7, }, { name: 'sus client', client: 'other', version: '1.8.9', + id: 8, }, + // { + // name: 'OneConfig ??', + // client: 'forge', + // version: '1.8.9', + // mods: 12, + // id: 5, + // }, ]; return (