diff --git a/dev/ItemList.css b/dev/ItemList.css index 42cce0f..4217441 100644 --- a/dev/ItemList.css +++ b/dev/ItemList.css @@ -1,18 +1,75 @@ .item-list { - background: var(--c-bg-1); - color: var(--c-fg-1); - list-style: none; - margin: 0; - padding: 0; + border-radius: var(--sp-1); + + ul { + background: var(--c-bg-1); + color: var(--c-fg-1); + list-style: none; + margin: 0; + padding: 0; + } + + li { + padding: var(--sp-1) var(--sp-2); + border-radius: var(--sp-1); + cursor: pointer; + + &.active, + &:hover { + background: var(--c-bg-3); + } + } + + 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; + } } -.item-list-item { - padding: var(--sp-1) var(--sp-2); +.item-list-header { + display: flex; + justify-content: space-between; + border-bottom: 1px solid var(--c-fg-3); +} + +.item-list-name { + padding-left: var(--sp-1); + cursor: pointer; + display: flex; + align-items: center; + justify-content: flex-start; + width: fit-content; border-radius: var(--sp-1); - cursor: pointer; - &.active, &:hover { background: var(--c-bg-3); } + + svg { + margin-left: var(--sp-1); + width: 0.875em; + height: 0.875em; + } +} + +.item-list-name.hide { + svg { + rotate: 0.75turn; + } } diff --git a/dev/ItemList.tsx b/dev/ItemList.tsx index 5edd635..b59193f 100644 --- a/dev/ItemList.tsx +++ b/dev/ItemList.tsx @@ -1,29 +1,150 @@ import "./ItemList.css"; -import { type Accessor, type Component, For } from "solid-js"; +import { + type Accessor, + type Component, + createEffect, + createSignal, + For, + Match, + Show, + type Signal, + Switch, +} from "solid-js"; +import { + ArrowNarrowDownIcon, + ArrowNarrowUpIcon, + ArrowsSortIcon, + ChevronDownIcon, +} from "#/dev/icons/index.ts"; export type ListItem = { label: string; isActive: boolean }; export type ItemHandler = (item: ListItem, index: number) => void; +export type Direction = "default" | "asc" | "desc"; + +function useDirection( + signal: Signal, +): [Accessor, (forcedDirection?: Direction) => Direction] { + const [direction, setDirection] = signal; + + return [ + direction, + (forcedDirection) => { + if (forcedDirection) { + setDirection(forcedDirection); + return direction(); + } + + switch (direction()) { + case "asc": { + setDirection("desc"); + break; + } + case "desc": { + setDirection("default"); + break; + } + default: { + setDirection("asc"); + } + } + + return direction(); + }, + ]; +} + export const ItemList: Component<{ + name: string; items: Accessor>; handler: ItemHandler; -}> = (props) => ( -
    - - {(item, index) => { - return ( -
  • = (props) => { + const [showList, setShowList] = createSignal(true); + const [items, setItems] = createSignal([...props.items()]); + const [direction, toggleDirection] = useDirection( + createSignal("default"), + ); + + createEffect(() => { + sortItems(props.items(), direction()); + }); + + const sortItems = (items: Array, direction: Direction) => { + if (direction === "default") { + setItems([...props.items()]); + return; + } + + const newItems = [...items]; + 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; + }); + + setItems(newItems); + }; + + return ( +
    +
    +
    setShowList(!showList())} + > + {props.name} + +
    + + +
    + + +
      + + {(item, index) => { + return ( +
    • props.handler(item, index())} + > + {item.label} +
    • + ); }} - onClick={() => props.handler(item, index())} - > - {item.label} - - ); - }} -
      -
    -); + +
+ + + ); +}; diff --git a/dev/RemoteItemList.css b/dev/RemoteItemList.css deleted file mode 100644 index d7aff7f..0000000 --- a/dev/RemoteItemList.css +++ /dev/null @@ -1,56 +0,0 @@ -.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: flex; - justify-content: space-between; - border-bottom: 1px solid var(--c-fg-3); -} - -.remote-item-list-name { - 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; - } -} - -.remote-item-list-name.hide { - svg { - rotate: 0.75turn; - } -} diff --git a/dev/RemoteItemList.tsx b/dev/RemoteItemList.tsx deleted file mode 100644 index 6b3cb29..0000000 --- a/dev/RemoteItemList.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import "./RemoteItemList.css"; -import { - type Accessor, - type Component, - createEffect, - createSignal, - Match, - Show, - type Signal, - Switch, -} from "solid-js"; -import { type ItemHandler, ItemList, type ListItem } from "#/dev/ItemList.tsx"; -import { - ArrowNarrowDownIcon, - ArrowNarrowUpIcon, - ArrowsSortIcon, - ChevronDownIcon, -} from "#/dev/icons/index.ts"; - -export type Direction = "default" | "asc" | "desc"; - -function useDirection( - signal: Signal, -): [Accessor, (forcedDirection?: Direction) => Direction] { - const [direction, setDirection] = signal; - - return [ - direction, - (forcedDirection) => { - if (forcedDirection) { - setDirection(forcedDirection); - return direction(); - } - - switch (direction()) { - case "asc": { - setDirection("desc"); - break; - } - case "desc": { - setDirection("default"); - break; - } - default: { - setDirection("asc"); - } - } - - return direction(); - }, - ]; -} - -export const RemoteItemList: Component<{ - name: string; - items: Accessor>; - handler: ItemHandler; -}> = (props) => { - const [showList, setShowList] = createSignal(true); - const [items, setItems] = createSignal([...props.items()]); - const [direction, toggleDirection] = useDirection( - createSignal("default"), - ); - - createEffect(() => { - sortItems(props.items(), direction()); - }); - - const sortItems = (items: Array, direction: Direction) => { - if (direction === "default") { - setItems([...props.items()]); - return; - } - - const newItems = [...items]; - 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; - }); - - setItems(newItems); - }; - - return ( -
-
-
setShowList(!showList())} - > - {props.name} - -
- - -
- - - -
- ); -}; diff --git a/dev/main.tsx b/dev/main.tsx index c753845..5b30f81 100644 --- a/dev/main.tsx +++ b/dev/main.tsx @@ -4,17 +4,15 @@ 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 { ItemList, type ListItem } from "#/dev/ItemList.tsx"; import { ArrowAutofitHeightIcon, ArrowAutofitWidthIcon, FileIcon, ZoomScanIcon, } from "#/dev/icons/index.ts"; -import type { Entity } from "#/engine/Entity"; import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts"; import { setScale, viewport } from "#/engine/Viewport.ts"; -import type { ListItem } from "./ItemList"; -import { RemoteItemList } from "./RemoteItemList"; async function fetchBrowserData(dir: string): Promise { const indexRef: string[] = await (await fetch(`/api/${dir}`)).json(); @@ -160,11 +158,7 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({ - +