feat: Instance card dragging
This commit is contained in:
parent
0f5b035e17
commit
71c98255a1
5 changed files with 167 additions and 21 deletions
|
|
@ -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",
|
||||
|
|
|
|||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div
|
||||
use:sortable
|
||||
class="sortable"
|
||||
classList={{
|
||||
'opacity-25': sortable.isActiveDraggable,
|
||||
'transition-transform': !!state.active.draggable,
|
||||
}}
|
||||
>
|
||||
{props.item}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function List() {
|
||||
const [items, setItems] = createSignal([1, 2, 3]);
|
||||
const [activeItem, setActiveItem] = createSignal<number | null>(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 (
|
||||
<DragDropProvider
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
collisionDetector={closestCenter}
|
||||
>
|
||||
<DragDropSensors />
|
||||
<div class="column self-stretch">
|
||||
<SortableProvider ids={ids()}>
|
||||
<For each={items()}>{item => <Item item={item} />}</For>
|
||||
</SortableProvider>
|
||||
</div>
|
||||
<DragOverlay>
|
||||
<div class="sortable">{activeItem()}</div>
|
||||
</DragOverlay>
|
||||
</DragDropProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function BrowserPage() {
|
||||
return (
|
||||
<h1>
|
||||
Browser
|
||||
</h1>
|
||||
<div class="flex flex-col gap-y-4">
|
||||
<h1>Browser</h1>
|
||||
<List />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div class="h-[152px] group flex flex-col rounded-xl bg-component-bg hover:bg-component-bg-hover active:bg-component-bg-pressed border border-gray-0.05 overflow-hidden">
|
||||
<div use:sortable={sortable} class="h-[152px] group flex flex-col rounded-xl bg-component-bg hover:bg-component-bg-hover active:bg-component-bg-pressed border border-gray-0.05 overflow-hidden">
|
||||
<div class="flex-1 relative overflow-hidden">
|
||||
<div
|
||||
class="absolute h-full w-full group-hover:!scale-110 transition-transform"
|
||||
|
|
@ -105,27 +121,44 @@ interface InstanceGroupProps {
|
|||
}
|
||||
|
||||
function InstanceGroup(props: InstanceGroupProps) {
|
||||
const [sorted, setSorted] = createSignal<InstanceCardProps[]>([]);
|
||||
// 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 (
|
||||
<div class="flex flex-col gap-y-4">
|
||||
<h4>{props.title}</h4>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<For each={sorted()}>
|
||||
{instance => (
|
||||
<InstanceCard {...instance} />
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
<DragDropProvider
|
||||
onDragStart={onDragStart}
|
||||
onDragEnd={onDragEnd}
|
||||
collisionDetector={closestCenter}
|
||||
>
|
||||
<DragDropSensors />
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<SortableProvider ids={ids()}>
|
||||
<For each={instances()}>{item => <InstanceCard {...item} />}</For>
|
||||
</SortableProvider>
|
||||
</div>
|
||||
</DragDropProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -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 (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue