init
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import type { Component, JSX } from "solid-js";
|
||||
import style from "./controls.module.css";
|
||||
|
||||
export const RangeSlider: Component<{
|
||||
name: string;
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
value: number;
|
||||
children?: JSX.Element;
|
||||
onChange?: (value: number) => void;
|
||||
onInput?: (value: number) => void;
|
||||
}> = (props) => (
|
||||
<label class={style.rangeSlider}>
|
||||
{props.children}
|
||||
<input
|
||||
type="range"
|
||||
name={props.name}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
step={props.step}
|
||||
value={props.value}
|
||||
onChange={(e) => props.onChange?.(e.target.valueAsNumber)}
|
||||
onInput={(e) => props.onInput?.(e.target.valueAsNumber)}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
@@ -0,0 +1,70 @@
|
||||
.rangeSlider {
|
||||
width: 100%;
|
||||
color: var(--c-fg-2);
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: var(--sp-2);
|
||||
font-family: var(--font-sans);
|
||||
font-weight: bold;
|
||||
padding: var(--sp-2);
|
||||
}
|
||||
|
||||
.rangeSlider [type="range"] {
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
border-radius: var(--sp-2);
|
||||
height: var(--sp-3);
|
||||
flex: auto;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: var(--sp-2);
|
||||
border-radius: var(--sp-3);
|
||||
color: transparent;
|
||||
background: var(--c-bg-3);
|
||||
border: none;
|
||||
}
|
||||
&::-webkit-slider-thumb {
|
||||
height: var(--sp-3);
|
||||
width: var(--sp-3);
|
||||
border-radius: var(--sp-3);
|
||||
border: none;
|
||||
background: var(--c-fg-1);
|
||||
margin-top: calc(var(--sp-1) * -1);
|
||||
--webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
&:focus::-webkit-slider-thumb {
|
||||
outline-width: 2px;
|
||||
outline-style: solid;
|
||||
outline-color: var(--c-primary);
|
||||
}
|
||||
|
||||
&::-moz-range-track {
|
||||
width: 100%;
|
||||
height: var(--sp-2);
|
||||
border-radius: var(--sp-3);
|
||||
color: transparent;
|
||||
background: var(--c-bg-3);
|
||||
border: none;
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
height: var(--sp-3);
|
||||
width: var(--sp-3);
|
||||
border-radius: var(--sp-3);
|
||||
border: none;
|
||||
background: var(--c-fg-1);
|
||||
}
|
||||
&:focus::-moz-range-thumb {
|
||||
outline-width: 2px;
|
||||
outline-style: solid;
|
||||
outline-color: var(--c-primary);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
.devTools {
|
||||
--font-sans:
|
||||
ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol", "Noto Color Emoji";
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
--font-mono:
|
||||
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
||||
"Courier New", monospace;
|
||||
|
||||
--rgb-blurple: 101, 114, 245;
|
||||
--c-blurple: rgb(var(--rgb-blurple));
|
||||
|
||||
--rgb-fuchsia: 238, 69, 158;
|
||||
--c-fuchsia: rgb(var(--rgb-fuchsia));
|
||||
|
||||
--rgb-green: 35, 165, 89;
|
||||
--c-green: rgb(var(--rgb-green));
|
||||
|
||||
--rgb-yellow: 240, 178, 50;
|
||||
--c-yellow: rgb(var(--rgb-yellow));
|
||||
|
||||
--rgb-orange: 255, 144, 0;
|
||||
--c-orange: rgb(var(--rgb-orange));
|
||||
|
||||
--rgb-red: 218, 55, 60;
|
||||
--c-red: rgb(var(--rgb-red));
|
||||
|
||||
--rgb-cyan: 95, 205, 228;
|
||||
--c-cyan: rgb(var(--rgb-cyan));
|
||||
|
||||
--rgb-pink: 246, 42, 245;
|
||||
--c-pink: rgb(var(--rgb-pink));
|
||||
|
||||
--rgb-gray: 117, 126, 138;
|
||||
--c-gray: rgb(var(--rgb-gray));
|
||||
|
||||
--rgb-white: 255, 255, 255;
|
||||
--c-white: rgb(var(--rgb-white));
|
||||
|
||||
--rgb-black: 30, 31, 34;
|
||||
--c-black: rgb(var(--rgb-black));
|
||||
|
||||
--c-primary: var(--c-blurple);
|
||||
--c-secondary: var(--c-fuchsia);
|
||||
--c-alert: var(--c-orange);
|
||||
--c-error: var(--c-red);
|
||||
|
||||
--c-bg-0: rgb(30, 31, 34);
|
||||
--c-bg-1: rgb(43, 45, 49);
|
||||
--c-bg-2: rgb(49, 51, 56);
|
||||
--c-bg-3: rgb(64, 66, 73);
|
||||
|
||||
--c-fg-0: rgb(255 255 225);
|
||||
--c-fg-1: rgb(219 222 225);
|
||||
--c-fg-2: rgb(181 186 193);
|
||||
--c-fg-3: rgb(113 116 120);
|
||||
|
||||
--sp-1: 4px;
|
||||
--sp-2: 8px;
|
||||
--sp-3: 16px;
|
||||
--sp-4: 24px;
|
||||
--sp-5: 32px;
|
||||
--sp-6: 48px;
|
||||
|
||||
height: 100%;
|
||||
min-width: 1px;
|
||||
max-width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
order: -1;
|
||||
font-size: medium;
|
||||
font-family: var(--font-sans);
|
||||
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline-width: 2px;
|
||||
outline-style: solid;
|
||||
outline-color: var(--c-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.toolBar {
|
||||
overflow: hidden;
|
||||
border-right: 1px solid var(--c-fg-3);
|
||||
background: var(--c-bg-1);
|
||||
color: var(--c-fg-1);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.toolBarResize {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: -3px;
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
cursor: ew-resize;
|
||||
user-select: none;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { type Component, createSignal, onMount } from "solid-js";
|
||||
import { render } from "solid-js/web";
|
||||
import { setScale, viewport } from "#/engine/Viewport.ts";
|
||||
import { RangeSlider } from "#/tools/controls/RangeSlider.tsx";
|
||||
import style from "./main.module.css";
|
||||
|
||||
function adjustGameContainer(gameContainer: HTMLElement, width: number): void {
|
||||
gameContainer.style = `position: relative; top: 0; left: ${width}px; width: ${document.body.offsetWidth - width}px;`;
|
||||
}
|
||||
|
||||
const DevTools: Component<{ gameContainer: HTMLElement }> = ({
|
||||
gameContainer,
|
||||
}) => {
|
||||
const [width, setWidth] = createSignal(320);
|
||||
let isResizing = false;
|
||||
|
||||
const startResizing = (): void => {
|
||||
isResizing = true;
|
||||
};
|
||||
|
||||
const stopResizing = (): void => {
|
||||
isResizing = false;
|
||||
};
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
if (isResizing) {
|
||||
setWidth(event.clientX);
|
||||
self.dispatchEvent(new Event("resize"));
|
||||
}
|
||||
};
|
||||
|
||||
adjustGameContainer(gameContainer, width());
|
||||
|
||||
onMount(() => {
|
||||
self.addEventListener("resize", () => {
|
||||
adjustGameContainer(gameContainer, width());
|
||||
});
|
||||
self.dispatchEvent(new Event("resize"));
|
||||
|
||||
document.addEventListener("mousemove", handleMouseMove);
|
||||
document.addEventListener("mouseup", stopResizing);
|
||||
});
|
||||
|
||||
return (
|
||||
<div class={style.devTools} style={{ width: `${width()}px` }}>
|
||||
<div class={style.toolBar}>
|
||||
<RangeSlider
|
||||
name="scale"
|
||||
min={1}
|
||||
max={8}
|
||||
step={1}
|
||||
value={viewport.initialScale}
|
||||
onInput={setScale}
|
||||
/>
|
||||
</div>
|
||||
<div class={style.toolBarResize} onMouseDown={startResizing}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export function use(container: HTMLElement): void {
|
||||
render(() => <DevTools gameContainer={container} />, document.body);
|
||||
}
|
||||
Reference in New Issue
Block a user