diff --git a/bun.lock b/bun.lock index 155cd4c..34a62b4 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,8 @@ "@astrojs/react": "^4.4.2", "@astrojs/tailwind": "^6.0.2", "@astrojs/vercel": "^9.0.4", + "@dnd-kit/helpers": "^0.5.0", + "@dnd-kit/react": "^0.5.0", "@fontsource-variable/dm-sans": "^5.0.6", "@formkit/auto-animate": "^0.8.2", "@iconify-json/fa6-brands": "^1.2.5", @@ -130,6 +132,20 @@ "@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="], + "@dnd-kit/abstract": ["@dnd-kit/abstract@0.5.0", "", { "dependencies": { "@dnd-kit/geometry": "^0.5.0", "@dnd-kit/state": "^0.5.0", "tslib": "^2.6.2" } }, "sha512-hi13iMJgjPX/KDYVKg5VeDIhmYiV6buc9bAX+tCLYf4QdyYjPbsXjn2sPo6m7fQ6SGJBEFgHJ2PemeKDUbwBaA=="], + + "@dnd-kit/collision": ["@dnd-kit/collision@0.5.0", "", { "dependencies": { "@dnd-kit/abstract": "^0.5.0", "@dnd-kit/geometry": "^0.5.0", "tslib": "^2.6.2" } }, "sha512-xUqRn3lS7oqLkT0AnnHS/STh/Czvwe1UapZFYiLbsUGxopMsQd4teaPCzPouOThoMdGEe+dHWjfqJl6t9iG4mQ=="], + + "@dnd-kit/dom": ["@dnd-kit/dom@0.5.0", "", { "dependencies": { "@dnd-kit/abstract": "^0.5.0", "@dnd-kit/collision": "^0.5.0", "@dnd-kit/geometry": "^0.5.0", "@dnd-kit/state": "^0.5.0", "tslib": "^2.6.2" } }, "sha512-f2xFJp5SYQ8EW/Fbtaa8iBb66hpkWc7qa8vU826KW11/tb44sH+AisZnGtwOOTWTQ0GraqBDr5ixTErww+eKXw=="], + + "@dnd-kit/geometry": ["@dnd-kit/geometry@0.5.0", "", { "dependencies": { "@dnd-kit/state": "^0.5.0", "tslib": "^2.6.2" } }, "sha512-ubHQS1CiSDH8ssYH2xG5BnpwPSFP1tStXXjug7/Ba6qnQdu/EUH47l6QXKIksQnnanfVfDf0aGeevRxgZlj28A=="], + + "@dnd-kit/helpers": ["@dnd-kit/helpers@0.5.0", "", { "dependencies": { "@dnd-kit/abstract": "^0.5.0", "tslib": "^2.6.2" } }, "sha512-i4y+51/icSw+OHMr/su19qhnmNhAzh8PnBwXvapFYTd+64oodIyJRiRkB+hhfxAfnur7RYSW8qacDTrXjg2XOg=="], + + "@dnd-kit/react": ["@dnd-kit/react@0.5.0", "", { "dependencies": { "@dnd-kit/abstract": "^0.5.0", "@dnd-kit/dom": "^0.5.0", "@dnd-kit/state": "^0.5.0", "tslib": "^2.6.2" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-abQPLI8lmfVE+v/n+pqy5WFxrw6T2Yg0UQZsL78dp5DKci7dKTVDjvLWqvass+XTFtzJmsZEjk1NdqE6xG8Jiw=="], + + "@dnd-kit/state": ["@dnd-kit/state@0.5.0", "", { "dependencies": { "@preact/signals-core": "^1.10.0", "tslib": "^2.6.2" } }, "sha512-y7XbabQqjF58Lk8YmDQuR8l6QjN+Kh4qlGEjUvHuIeasLk1QP+9L5diXS98VMxQIivyMmUtX2//f+3N7qPJX4w=="], + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], @@ -320,6 +336,8 @@ "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + "@preact/signals-core": ["@preact/signals-core@1.14.4", "", {}, "sha512-HNB6HYeYKhQbJ1aKl+YRjrS4+QWHLKX6qKoUsfS/m0vqzsVaEBiZiaKbG/e+NKk2ch5ALQr/ihWaMHxiCuuWHA=="], + "@prequist/lanyard": ["@prequist/lanyard@1.1.0", "", {}, "sha512-OBBRIoFQZgDF2t7/MBUw35YYmwOU9WAVvvvLHQHrwOw0JrCuTpsl1OI9kSjGjOfsqhB2cHIGYQg5nYPkOsg9nw=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], diff --git a/package.json b/package.json index 7bf99ee..ab3a29b 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "@astrojs/react": "^4.4.2", "@astrojs/tailwind": "^6.0.2", "@astrojs/vercel": "^9.0.4", + "@dnd-kit/helpers": "^0.5.0", + "@dnd-kit/react": "^0.5.0", "@fontsource-variable/dm-sans": "^5.0.6", "@formkit/auto-animate": "^0.8.2", "@iconify-json/fa6-brands": "^1.2.5", diff --git a/src/components/port/TierList.tsx b/src/components/port/TierList.tsx new file mode 100644 index 0000000..6122486 --- /dev/null +++ b/src/components/port/TierList.tsx @@ -0,0 +1,121 @@ +import { useDroppable, DragDropProvider } from "@dnd-kit/react"; +import { useSortable } from "@dnd-kit/react/sortable"; +import { CollisionPriority } from "@dnd-kit/abstract"; +import { move } from "@dnd-kit/helpers"; + +import React, { useEffect, useState } from "react"; + +interface Element { + id: string; + name: string; + color: string; + area: string; +} + +function Column({ children, id }: { children: React.ReactNode; id: string }) { + const { isDropTarget, ref } = useDroppable({ + id, + type: "column", + accept: "item", + collisionPriority: CollisionPriority.Low + }); + + const colors: Record = { + S: "bg-red-200", + A: "bg-orange-200", + B: "bg-yellow-200", + C: "bg-green-200", + F: "bg-blue-200" + }; + + return ( +
+ {!id.startsWith("_") ?
{id} Tier
: <>} + +
+ {children} +
+
+ ); +} + +function Item(props: { element: Element; index: number; column: string }) { + const { ref, isDragging } = useSortable({ + id: props.element.id, + index: props.index, + type: "item", + accept: "item", + group: props.column + }); + + return ( + + ); +} + +export default function TierList() { + const [items, setItems] = useState({ + S: [], + A: [], + B: [], + C: [], + F: [], + _: [ + { id: "heytea", name: "HEYTEA", area: "Harvard Avenue", color: "bg-orange-300" }, + { id: "ygfmalatang", name: "YGF Malatang", area: "Jamboree Promenade", color: "bg-purple-300" } + ] + }); + + useEffect(() => { + const items = localStorage.getItem("items"); + if (!items) return; + + console.log(items); + + setItems(JSON.parse(items)); + }, []); + + useEffect(() => { + localStorage.setItem("items", JSON.stringify(items)); + console.log(items); + }, [items]); + + const [columnOrder, setColumnOrder] = useState(() => Object.keys(items)); + + return ( +
+ { + const { source, target } = event.operation; + + if (source?.type === "column") return; + + setItems((items) => move(items, event)); + }} + onDragEnd={(event) => { + const { source, target } = event.operation; + + // @ts-expect-error Testing + if (event.canceled || source.type !== "column") return; + + setColumnOrder((columns) => move(columns, event)); + }} + > + {Object.entries(items).map(([column, items]) => ( + + {items.map((element, index) => ( + + ))} + + ))} + +
+ ); +} diff --git a/src/pages/tierlist.astro b/src/pages/tierlist.astro new file mode 100644 index 0000000..f5c87c0 --- /dev/null +++ b/src/pages/tierlist.astro @@ -0,0 +1,13 @@ +--- +import Layout from "../layouts/Layout.astro"; +import TierList from "../components/port/TierList"; +import { Icon } from "astro-icon/components"; +--- + + +
+ + + +
+