This commit is contained in:
kolaflash
2025-12-29 16:56:00 +01:00
parent 323b7fbd33
commit 74d22d425d
14 changed files with 315 additions and 8 deletions
+2 -1
View File
@@ -7,7 +7,8 @@
}, },
"suspicious": { "suspicious": {
"noTsIgnore": "off", "noTsIgnore": "off",
"noAssignInExpressions": "off" "noAssignInExpressions": "off",
"noFallthroughSwitchClause": "warn"
}, },
"correctness": { "correctness": {
"useParseIntRadix": "off" "useParseIntRadix": "off"
+3 -3
View File
@@ -3,18 +3,18 @@
margin-left: calc(var(--sp-2) * -1); margin-left: calc(var(--sp-2) * -1);
} }
.file-list { .file-browser-list {
margin: 0; margin: 0;
list-style: none; list-style: none;
padding: 0 0 0 var(--sp-2); padding: 0 0 0 var(--sp-2);
} }
.file-item { .file-brwoser-item {
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
} }
.file-label { .file-browser-label {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
+4 -4
View File
@@ -31,7 +31,7 @@ export const FileBrowser: Component<{
}> = ({ name, entry }) => { }> = ({ name, entry }) => {
return ( return (
<div <div
class="file-label" class="file-browser-label"
classList={{ classList={{
active: entry.isActive, active: entry.isActive,
}} }}
@@ -52,7 +52,7 @@ export const FileBrowser: Component<{
return ( return (
<> <>
<div class="file-label" onClick={() => setIsOpen(!isOpen())}> <div class="file-browser-label" onClick={() => setIsOpen(!isOpen())}>
{isOpen() ? <FolderOpenIcon /> : <FolderIcon />} {isOpen() ? <FolderOpenIcon /> : <FolderIcon />}
<span>{name}</span> <span>{name}</span>
</div> </div>
@@ -66,13 +66,13 @@ export const FileBrowser: Component<{
const FileList: Component<{ folder: BrowserFolder }> = (props) => { const FileList: Component<{ folder: BrowserFolder }> = (props) => {
return ( return (
<ul class="file-list"> <ul class="file-browser-list">
<For each={[...props.folder.entries()]}> <For each={[...props.folder.entries()]}>
{(item, index) => { {(item, index) => {
const [name, entry] = item; const [name, entry] = item;
return ( return (
<li class="file-item"> <li class="file-browser-item">
{isFolder(entry) ? ( {isFolder(entry) ? (
<FolderEntry folder={entry} name={name} open={index() < 1} /> <FolderEntry folder={entry} name={name} open={index() < 1} />
) : ( ) : (
+18
View File
@@ -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);
}
}
+83
View File
@@ -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<ListItem>,
): (direction?: Direction) => Array<ListItem> {
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<Array<ListItem>>;
handler: ItemHandler;
}> = (props) => (
<ul class="item-list">
<For each={props.items()}>
{(item, index) => {
return (
<li
class="item-list-item"
classList={{
active: item.isActive,
}}
onClick={() => props.handler(item, index())}
>
{item.label}
</li>
);
}}
</For>
</ul>
);
+50
View File
@@ -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;
}
}
+59
View File
@@ -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<Array<ListItem>>;
}> = () => {
const [items, setItems] = createSignal<Array<ListItem>>([
{
label: "foo",
isActive: false,
},
{
label: "bar",
isActive: false,
},
{
label: "lol",
isActive: true,
},
]);
const getSorted = useSort(items());
const toggleDirection = useDirection();
return (
<div class="remote-item-list">
<div class="remote-item-list-header">
<div class="remote-item-list-label" role="button">
Items
<ChevronDownIcon />
</div>
<button
type="button"
onClick={() => {
setItems(getSorted(toggleDirection()));
}}
>
<ArrowsSortIcon />
</button>
<button type="button">
<ReloadIcon />
</button>
</div>
<ItemList items={items} handler={console.log} />
</div>
);
};
+17
View File
@@ -0,0 +1,17 @@
export const ArrowNarrowDownIcon = () => {
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={2}
d="M12 5v14m4-4l-4 4m-4-4l4 4"
/>
</svg>;
};
+17
View File
@@ -0,0 +1,17 @@
export const ArrowNarrowUpIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={2}
d="M12 5v14m4-10l-4-4M8 9l4-4"
/>
</svg>
);
+17
View File
@@ -0,0 +1,17 @@
export const ArrowsSortIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={2}
d="m3 9l4-4l4 4M7 5v14m14-4l-4 4l-4-4m4 4V5"
/>
</svg>
);
+17
View File
@@ -0,0 +1,17 @@
export const ChevronDownIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
>
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={2}
d="m6 9l6 6l6-6"
/>
</svg>
);
+19
View File
@@ -0,0 +1,19 @@
export const ReloadIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width={2}
>
<path d="M19.933 13.041a8 8 0 1 1-9.925-8.788c3.899-1 7.935 1.007 9.425 4.747" />
<path d="M20 4v5h-5" />
</g>
</svg>
);
+5
View File
@@ -1,5 +1,9 @@
export * from "./ArrowAutofitHeight.tsx"; export * from "./ArrowAutofitHeight.tsx";
export * from "./ArrowAutofitWidth.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 "./File.tsx";
export * from "./FileDelta.tsx"; export * from "./FileDelta.tsx";
export * from "./FileMusic.tsx"; export * from "./FileMusic.tsx";
@@ -16,6 +20,7 @@ export * from "./Polygon.tsx";
export * from "./Refresh.tsx"; export * from "./Refresh.tsx";
export * from "./RefreshAlert.tsx"; export * from "./RefreshAlert.tsx";
export * from "./RefreshDot.tsx"; export * from "./RefreshDot.tsx";
export * from "./Reload.tsx";
export * from "./Script.tsx"; export * from "./Script.tsx";
export * from "./StackBackward.tsx"; export * from "./StackBackward.tsx";
export * from "./StackForward.tsx"; export * from "./StackForward.tsx";
+4
View File
@@ -4,6 +4,7 @@ import { render } from "solid-js/web";
import { InputField } from "#/dev/controls/InputField.tsx"; import { InputField } from "#/dev/controls/InputField.tsx";
import { RangeSlider } from "#/dev/controls/RangeSlider.tsx"; import { RangeSlider } from "#/dev/controls/RangeSlider.tsx";
import { type BrowserFolder, FileBrowser } from "#/dev/FileBrowser.tsx"; import { type BrowserFolder, FileBrowser } from "#/dev/FileBrowser.tsx";
import type { ListItem } from "#/dev/ItemList.tsx";
import { import {
ArrowAutofitHeightIcon, ArrowAutofitHeightIcon,
ArrowAutofitWidthIcon, ArrowAutofitWidthIcon,
@@ -13,6 +14,7 @@ import {
import type { Entity } from "#/engine/Entity"; import type { Entity } from "#/engine/Entity";
import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts"; import { currentScene, loadScene, type SceneData } from "#/engine/Scene.ts";
import { setScale, viewport } from "#/engine/Viewport.ts"; import { setScale, viewport } from "#/engine/Viewport.ts";
import { RemoteItemList } from "./RemoteItemList";
async function fetchBrowserData(dir: string): Promise<BrowserFolder> { async function fetchBrowserData(dir: string): Promise<BrowserFolder> {
const indexRef: string[] = await (await fetch(`/api/${dir}`)).json(); const indexRef: string[] = await (await fetch(`/api/${dir}`)).json();
@@ -169,6 +171,8 @@ const DevTools: Component<{ gameContainer: HTMLElement }> = ({
<FileBrowser root={scenes} handler={setCurrentScene} /> <FileBrowser root={scenes} handler={setCurrentScene} />
<FileBrowser root={entities} handler={setActiveEntity} /> <FileBrowser root={entities} handler={setActiveEntity} />
<RemoteItemList fetchItems={async () => []} />
</div> </div>
<div class="tool-bar-resize" onMouseDown={startResizing}></div> <div class="tool-bar-resize" onMouseDown={startResizing}></div>
</div> </div>