From 74d22d425d353ce305fecbf37ff8b17036b9fe15 Mon Sep 17 00:00:00 2001 From: kolaflash Date: Mon, 29 Dec 2025 16:56:00 +0100 Subject: [PATCH] WIP --- biome.json | 3 +- dev/FileBrowser.css | 6 +-- dev/FileBrowser.tsx | 8 ++-- dev/ItemList.css | 18 ++++++++ dev/ItemList.tsx | 83 +++++++++++++++++++++++++++++++++++ dev/RemoteItemList.css | 50 +++++++++++++++++++++ dev/RemoteItemList.tsx | 59 +++++++++++++++++++++++++ dev/icons/ArrowNarrowDown.tsx | 17 +++++++ dev/icons/ArrowNarrowUp.tsx | 17 +++++++ dev/icons/ArrowsSort.tsx | 17 +++++++ dev/icons/ChevronDown.tsx | 17 +++++++ dev/icons/Reload.tsx | 19 ++++++++ dev/icons/index.ts | 5 +++ dev/main.tsx | 4 ++ 14 files changed, 315 insertions(+), 8 deletions(-) create mode 100644 dev/ItemList.css create mode 100644 dev/ItemList.tsx create mode 100644 dev/RemoteItemList.css create mode 100644 dev/RemoteItemList.tsx create mode 100644 dev/icons/ArrowNarrowDown.tsx create mode 100644 dev/icons/ArrowNarrowUp.tsx create mode 100644 dev/icons/ArrowsSort.tsx create mode 100644 dev/icons/ChevronDown.tsx create mode 100644 dev/icons/Reload.tsx diff --git a/biome.json b/biome.json index 96555ae..7c3d6da 100644 --- a/biome.json +++ b/biome.json @@ -7,7 +7,8 @@ }, "suspicious": { "noTsIgnore": "off", - "noAssignInExpressions": "off" + "noAssignInExpressions": "off", + "noFallthroughSwitchClause": "warn" }, "correctness": { "useParseIntRadix": "off" diff --git a/dev/FileBrowser.css b/dev/FileBrowser.css index b94cbdb..a6b9e7f 100644 --- a/dev/FileBrowser.css +++ b/dev/FileBrowser.css @@ -3,18 +3,18 @@ margin-left: calc(var(--sp-2) * -1); } -.file-list { +.file-browser-list { margin: 0; list-style: none; padding: 0 0 0 var(--sp-2); } -.file-item { +.file-brwoser-item { display: flex; flex-flow: column nowrap; } -.file-label { +.file-browser-label { display: flex; justify-content: flex-start; align-items: center; diff --git a/dev/FileBrowser.tsx b/dev/FileBrowser.tsx index 6e72a67..465971e 100644 --- a/dev/FileBrowser.tsx +++ b/dev/FileBrowser.tsx @@ -31,7 +31,7 @@ export const FileBrowser: Component<{ }> = ({ name, entry }) => { return (
-
setIsOpen(!isOpen())}> +
setIsOpen(!isOpen())}> {isOpen() ? : } {name}
@@ -66,13 +66,13 @@ export const FileBrowser: Component<{ const FileList: Component<{ folder: BrowserFolder }> = (props) => { return ( -
    +
      {(item, index) => { const [name, entry] = item; return ( -
    • +
    • {isFolder(entry) ? ( ) : ( diff --git a/dev/ItemList.css b/dev/ItemList.css new file mode 100644 index 0000000..42cce0f --- /dev/null +++ b/dev/ItemList.css @@ -0,0 +1,18 @@ +.item-list { + background: var(--c-bg-1); + color: var(--c-fg-1); + list-style: none; + margin: 0; + padding: 0; +} + +.item-list-item { + padding: var(--sp-1) var(--sp-2); + border-radius: var(--sp-1); + cursor: pointer; + + &.active, + &:hover { + background: var(--c-bg-3); + } +} diff --git a/dev/ItemList.tsx b/dev/ItemList.tsx new file mode 100644 index 0000000..06176d3 --- /dev/null +++ b/dev/ItemList.tsx @@ -0,0 +1,83 @@ +import "./ItemList.css"; +import { type Accessor, type Component, For } from "solid-js"; + +export type ListItem = { label: string; isActive: boolean }; + +export type ItemHandler = (item: ListItem, index: number) => void; + +export type Direction = undefined | "asc" | "desc"; + +export function useSort( + items: Array, +): (direction?: Direction) => Array { + const itemsRef = [...items]; + + return (direction) => { + if (!direction) { + return [...itemsRef]; + } + const newItems = [...itemsRef]; + + newItems.sort((a, b) => { + const labelA = a.label.toLocaleLowerCase(); + const labelB = b.label.toLocaleLowerCase(); + + if (labelA < labelB) { + return direction === "asc" ? -1 : 1; + } + + if (labelA > labelB) { + return direction === "asc" ? 1 : -1; + } + + return 0; + }); + + return newItems; + }; +} + +export function useDirection(initialDirection?: Direction): () => Direction { + let direction: Direction = initialDirection; + + return () => { + switch (direction) { + case "asc": { + direction = "desc"; + break; + } + case "desc": { + direction = undefined; + break; + } + default: { + direction = "asc"; + } + } + + return direction; + }; +} + +export const ItemList: Component<{ + items: Accessor>; + handler: ItemHandler; +}> = (props) => ( +
        + + {(item, index) => { + return ( +
      • props.handler(item, index())} + > + {item.label} +
      • + ); + }} +
        +
      +); diff --git a/dev/RemoteItemList.css b/dev/RemoteItemList.css new file mode 100644 index 0000000..c580c65 --- /dev/null +++ b/dev/RemoteItemList.css @@ -0,0 +1,50 @@ +.remote-item-list { + border-radius: var(--sp-1); + + button { + color: inherit; + border-radius: var(--sp-1); + border: none; + background: transparent; + padding: var(--sp-1); + margin-left: var(--sp-1); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + } + button:hover { + background: var(--c-bg-3); + } + + svg { + width: 1.5em; + height: 1.5em; + } +} + +.remote-item-list-header { + display: grid; + grid-template-columns: 1fr auto auto; + border-bottom: 1px solid var(--c-fg-3); +} + +.remote-item-list-label { + padding-left: var(--sp-1); + cursor: pointer; + display: flex; + align-items: center; + justify-content: flex-start; + width: fit-content; + border-radius: var(--sp-1); + + &:hover { + background: var(--c-bg-3); + } + + svg { + margin-left: var(--sp-1); + width: 0.875em; + height: 0.875em; + } +} diff --git a/dev/RemoteItemList.tsx b/dev/RemoteItemList.tsx new file mode 100644 index 0000000..b394ce6 --- /dev/null +++ b/dev/RemoteItemList.tsx @@ -0,0 +1,59 @@ +import "./RemoteItemList.css"; +import { type Component, createSignal } from "solid-js"; +import { + ItemList, + type ListItem, + useDirection, + useSort, +} from "#/dev/ItemList.tsx"; +import { + ArrowNarrowDownIcon, + ArrowNarrowUpIcon, + ArrowsSortIcon, + ChevronDownIcon, + ReloadIcon, +} from "#/dev/icons/index.ts"; + +export const RemoteItemList: Component<{ + fetchItems: () => Promise>; +}> = () => { + const [items, setItems] = createSignal>([ + { + label: "foo", + isActive: false, + }, + { + label: "bar", + isActive: false, + }, + { + label: "lol", + isActive: true, + }, + ]); + const getSorted = useSort(items()); + const toggleDirection = useDirection(); + + return ( +
      +
      +
      + Items + +
      + + +
      + +
      + ); +}; diff --git a/dev/icons/ArrowNarrowDown.tsx b/dev/icons/ArrowNarrowDown.tsx new file mode 100644 index 0000000..721343c --- /dev/null +++ b/dev/icons/ArrowNarrowDown.tsx @@ -0,0 +1,17 @@ +export const ArrowNarrowDownIcon = () => { + + + ; +}; diff --git a/dev/icons/ArrowNarrowUp.tsx b/dev/icons/ArrowNarrowUp.tsx new file mode 100644 index 0000000..ed8239d --- /dev/null +++ b/dev/icons/ArrowNarrowUp.tsx @@ -0,0 +1,17 @@ +export const ArrowNarrowUpIcon = () => ( + + + +); diff --git a/dev/icons/ArrowsSort.tsx b/dev/icons/ArrowsSort.tsx new file mode 100644 index 0000000..937341c --- /dev/null +++ b/dev/icons/ArrowsSort.tsx @@ -0,0 +1,17 @@ +export const ArrowsSortIcon = () => ( + + + +); diff --git a/dev/icons/ChevronDown.tsx b/dev/icons/ChevronDown.tsx new file mode 100644 index 0000000..fa13551 --- /dev/null +++ b/dev/icons/ChevronDown.tsx @@ -0,0 +1,17 @@ +export const ChevronDownIcon = () => ( + + + +); diff --git a/dev/icons/Reload.tsx b/dev/icons/Reload.tsx new file mode 100644 index 0000000..361782a --- /dev/null +++ b/dev/icons/Reload.tsx @@ -0,0 +1,19 @@ +export const ReloadIcon = () => ( + + + + + + +); diff --git a/dev/icons/index.ts b/dev/icons/index.ts index c245b88..1e05d1f 100644 --- a/dev/icons/index.ts +++ b/dev/icons/index.ts @@ -1,5 +1,9 @@ export * from "./ArrowAutofitHeight.tsx"; export * from "./ArrowAutofitWidth.tsx"; +export * from "./ArrowNarrowDown.tsx"; +export * from "./ArrowNarrowUp.tsx"; +export * from "./ArrowsSort.tsx"; +export * from "./ChevronDown.tsx"; export * from "./File.tsx"; export * from "./FileDelta.tsx"; export * from "./FileMusic.tsx"; @@ -16,6 +20,7 @@ export * from "./Polygon.tsx"; export * from "./Refresh.tsx"; export * from "./RefreshAlert.tsx"; export * from "./RefreshDot.tsx"; +export * from "./Reload.tsx"; export * from "./Script.tsx"; export * from "./StackBackward.tsx"; export * from "./StackForward.tsx"; diff --git a/dev/main.tsx b/dev/main.tsx index ac534a8..8520a83 100644 --- a/dev/main.tsx +++ b/dev/main.tsx @@ -4,6 +4,7 @@ import { render } from "solid-js/web"; import { InputField } from "#/dev/controls/InputField.tsx"; import { RangeSlider } from "#/dev/controls/RangeSlider.tsx"; import { type BrowserFolder, FileBrowser } from "#/dev/FileBrowser.tsx"; +import type { ListItem } from "#/dev/ItemList.tsx"; import { ArrowAutofitHeightIcon, ArrowAutofitWidthIcon, @@ -13,6 +14,7 @@ import { import type { Entity } from "#/engine/Entity"; import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts"; import { setScale, viewport } from "#/engine/Viewport.ts"; +import { RemoteItemList } from "./RemoteItemList"; async function fetchBrowserData(dir: string): Promise { const indexRef: string[] = await (await fetch(`/api/${dir}`)).json(); @@ -169,6 +171,8 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({ + + []} />