WIP
This commit is contained in:
+3
-3
@@ -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;
|
||||
|
||||
+4
-4
@@ -31,7 +31,7 @@ export const FileBrowser: Component<{
|
||||
}> = ({ name, entry }) => {
|
||||
return (
|
||||
<div
|
||||
class="file-label"
|
||||
class="file-browser-label"
|
||||
classList={{
|
||||
active: entry.isActive,
|
||||
}}
|
||||
@@ -52,7 +52,7 @@ export const FileBrowser: Component<{
|
||||
|
||||
return (
|
||||
<>
|
||||
<div class="file-label" onClick={() => setIsOpen(!isOpen())}>
|
||||
<div class="file-browser-label" onClick={() => setIsOpen(!isOpen())}>
|
||||
{isOpen() ? <FolderOpenIcon /> : <FolderIcon />}
|
||||
<span>{name}</span>
|
||||
</div>
|
||||
@@ -66,13 +66,13 @@ export const FileBrowser: Component<{
|
||||
|
||||
const FileList: Component<{ folder: BrowserFolder }> = (props) => {
|
||||
return (
|
||||
<ul class="file-list">
|
||||
<ul class="file-browser-list">
|
||||
<For each={[...props.folder.entries()]}>
|
||||
{(item, index) => {
|
||||
const [name, entry] = item;
|
||||
|
||||
return (
|
||||
<li class="file-item">
|
||||
<li class="file-browser-item">
|
||||
{isFolder(entry) ? (
|
||||
<FolderEntry folder={entry} name={name} open={index() < 1} />
|
||||
) : (
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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";
|
||||
|
||||
@@ -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<BrowserFolder> {
|
||||
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={entities} handler={setActiveEntity} />
|
||||
|
||||
<RemoteItemList fetchItems={async () => []} />
|
||||
</div>
|
||||
<div class="tool-bar-resize" onMouseDown={startResizing}></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user