feat: add theming basics
This commit is contained in:
parent
f9d211eb72
commit
9b76299272
@ -1,12 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/svelte.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/svelte.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -3,12 +3,13 @@
|
||||
import { OrbitControls } from "@threlte/extras";
|
||||
import { onMount } from "svelte";
|
||||
import { MOUSE, type OrthographicCamera } from "three";
|
||||
import type { OrbitControls as OrbitControlsType } from "three/examples/jsm/Addons.js";
|
||||
|
||||
export let camera: OrthographicCamera | undefined = undefined;
|
||||
export let maxZoom = 150;
|
||||
export let minZoom = 4;
|
||||
|
||||
let controls: OrbitControls | undefined = undefined;
|
||||
export let controls: OrbitControlsType | undefined = undefined;
|
||||
|
||||
export const position: [number, number, number] = [0, 1, 0];
|
||||
|
||||
@ -56,8 +57,8 @@
|
||||
|
||||
<T.OrthographicCamera bind:ref={camera} position.y={10} makeDefault>
|
||||
<OrbitControls
|
||||
args={[camera, window]}
|
||||
mouseButtons={{ LEFT: MOUSE.PAN, MIDDLE: 0, RIGHT: 0 }}
|
||||
args={[camera, document.body]}
|
||||
mouseButtons={{ LEFT: 0, MIDDLE: 0, RIGHT: MOUSE.PAN }}
|
||||
bind:ref={controls}
|
||||
enableZoom={true}
|
||||
zoomSpeed={2}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { Node } from "$lib/types";
|
||||
import { getContext, onMount } from "svelte";
|
||||
import { getContext } from "svelte";
|
||||
import NodeHeader from "./NodeHeader.svelte";
|
||||
import NodeParameter from "./NodeParameter.svelte";
|
||||
import { activeNodeId, selectedNodes } from "./graph/stores";
|
||||
@ -38,7 +38,6 @@
|
||||
<NodeParameter
|
||||
{node}
|
||||
id={key}
|
||||
index={i}
|
||||
input={value}
|
||||
isLast={i == parameters.length - 1}
|
||||
/>
|
||||
@ -51,25 +50,24 @@
|
||||
box-sizing: border-box;
|
||||
user-select: none !important;
|
||||
cursor: pointer;
|
||||
width: 100px;
|
||||
width: 200px;
|
||||
color: var(--text-color);
|
||||
transform: translate3d(var(--nx), var(--ny), 0);
|
||||
z-index: 1;
|
||||
font-weight: 300;
|
||||
font-size: 0.5em;
|
||||
display: none;
|
||||
--stroke: #777;
|
||||
--stroke-width: 0.1px;
|
||||
--stroke: var(--background-color-lighter);
|
||||
--stroke-width: 2px;
|
||||
}
|
||||
|
||||
.node.active {
|
||||
--stroke: white;
|
||||
--stroke-width: 0.3px;
|
||||
--stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node.selected {
|
||||
--stroke: #f2be90;
|
||||
--stroke-width: 0.2px;
|
||||
--stroke-width: 1px;
|
||||
}
|
||||
|
||||
.node.in-view {
|
||||
|
@ -81,7 +81,7 @@
|
||||
.wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.click-target {
|
||||
@ -89,8 +89,8 @@
|
||||
right: 0px;
|
||||
top: 50%;
|
||||
transform: translateX(50%) translateY(-50%);
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
z-index: 100;
|
||||
border-radius: 50%;
|
||||
/* background: red; */
|
||||
@ -114,7 +114,9 @@
|
||||
|
||||
svg path {
|
||||
stroke-width: 0.2px;
|
||||
transition: 0.2s;
|
||||
transition:
|
||||
d 0.3s ease,
|
||||
fill 0.3s ease;
|
||||
fill: var(--background-color-lighter);
|
||||
stroke: var(--stroke);
|
||||
stroke-width: var(--stroke-width);
|
||||
@ -125,7 +127,7 @@
|
||||
font-size: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 5px;
|
||||
padding-left: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,9 @@
|
||||
aspectRatio,
|
||||
});
|
||||
const pathHover = createNodePath({
|
||||
depth: 8,
|
||||
height: 24,
|
||||
y: 50,
|
||||
depth: 6,
|
||||
height: 18,
|
||||
y: 50.5,
|
||||
cornerBottom,
|
||||
leftBump,
|
||||
aspectRatio,
|
||||
@ -102,7 +102,7 @@
|
||||
.wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
height: 100px;
|
||||
transform: translateY(-0.5px);
|
||||
}
|
||||
|
||||
@ -116,13 +116,13 @@
|
||||
}
|
||||
|
||||
.small.target {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.large.target {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
cursor: unset;
|
||||
pointer-events: none;
|
||||
}
|
||||
@ -133,14 +133,13 @@
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
padding: 2px 5px;
|
||||
padding: 10px 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: space-around;
|
||||
box-sizing: border-box;
|
||||
opacity: calc((2 * var(--cz)) / 150 - 0.5);
|
||||
opacity: calc((var(--cz) - 10) / 20);
|
||||
opacity: var(--input-opacity);
|
||||
}
|
||||
|
||||
:global(.zoom-small) .content {
|
||||
@ -150,14 +149,11 @@
|
||||
.input {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
border-radius: 3px;
|
||||
font-size: 1em;
|
||||
padding: 2px 2px;
|
||||
padding: 10px;
|
||||
background: #111;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 1em;
|
||||
background: var(--background-color-lighter);
|
||||
}
|
||||
|
||||
svg {
|
||||
@ -172,7 +168,9 @@
|
||||
}
|
||||
|
||||
svg path {
|
||||
transition: 0.2s;
|
||||
transition:
|
||||
d 0.3s ease,
|
||||
fill 0.3s ease;
|
||||
fill: var(--background-color);
|
||||
stroke: var(--stroke);
|
||||
stroke-width: var(--stroke-width);
|
||||
|
@ -4,13 +4,10 @@ varying vec2 vUv;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
uniform float width;
|
||||
uniform float height;
|
||||
uniform float cx;
|
||||
uniform float cy;
|
||||
uniform float cz;
|
||||
uniform float minZ;
|
||||
uniform float maxZ;
|
||||
uniform vec2 dimensions;
|
||||
uniform vec3 camPos;
|
||||
uniform vec2 zoomLimits;
|
||||
uniform vec3 backgroundColor;
|
||||
|
||||
float grid(float x, float y, float divisions, float thickness) {
|
||||
x = fract(x * divisions);
|
||||
@ -47,6 +44,17 @@ float lerp(float a, float b,float t) {
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
float cx = camPos.x;
|
||||
float cy = camPos.y;
|
||||
float cz = camPos.z;
|
||||
|
||||
float width = dimensions.x;
|
||||
float height = dimensions.y;
|
||||
|
||||
float minZ = zoomLimits.x;
|
||||
float maxZ = zoomLimits.y;
|
||||
|
||||
float divisions = 0.1/cz;
|
||||
float thickness = 0.05/cz;
|
||||
float delta = 0.1 / 2.0;
|
||||
@ -84,7 +92,7 @@ void main(void) {
|
||||
float c = mix(large, small, min(nz*2.0+0.05, 1.0));
|
||||
c = mix(c, xsmall, max(min((nz-0.3)/0.7, 1.0), 0.0));
|
||||
|
||||
//c = xsmall;
|
||||
vec3 color = mix(backgroundColor, vec3(1.0), c*0.5);
|
||||
|
||||
gl_FragColor = vec4(c, c, c, 1.0);
|
||||
gl_FragColor = vec4(color, 1.0);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { T } from "@threlte/core";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import BackgroundVert from "./Background.vert";
|
||||
import BackgroundFrag from "./Background.frag";
|
||||
import { Color } from "three";
|
||||
import { colors } from "../graph/stores";
|
||||
|
||||
export let minZoom = 4;
|
||||
export let maxZoom = 150;
|
||||
@ -34,33 +35,23 @@
|
||||
vertexShader={BackgroundVert}
|
||||
fragmentShader={BackgroundFrag}
|
||||
uniforms={{
|
||||
cx: {
|
||||
value: 0,
|
||||
camPos: {
|
||||
value: [0, 1, 0],
|
||||
},
|
||||
cy: {
|
||||
value: 0,
|
||||
backgroundColor: {
|
||||
value: [0, 0, 0],
|
||||
},
|
||||
cz: {
|
||||
value: 30,
|
||||
zoomLimits: {
|
||||
value: [2, 50],
|
||||
},
|
||||
minZ: {
|
||||
value: minZoom,
|
||||
},
|
||||
maxZ: {
|
||||
value: maxZoom,
|
||||
},
|
||||
height: {
|
||||
value: 100,
|
||||
},
|
||||
width: {
|
||||
value: 100,
|
||||
dimensions: {
|
||||
value: [100, 100],
|
||||
},
|
||||
}}
|
||||
uniforms.cx.value={cameraPosition[0]}
|
||||
uniforms.cy.value={cameraPosition[1]}
|
||||
uniforms.cz.value={cameraPosition[2]}
|
||||
uniforms.width.value={width}
|
||||
uniforms.height.value={height}
|
||||
uniforms.camPos.value={cameraPosition}
|
||||
uniforms.backgroundColor.value={$colors.backgroundColorDarker}
|
||||
uniforms.zoomLimits.value={[minZoom, maxZoom]}
|
||||
uniforms.dimensions.value={[width, height]}
|
||||
/>
|
||||
</T.Mesh>
|
||||
</T.Group>
|
||||
|
@ -22,6 +22,10 @@
|
||||
|
||||
let mesh: Mesh;
|
||||
|
||||
import { colors } from "../graph/stores";
|
||||
|
||||
$: color = $colors.backgroundColorLighter;
|
||||
|
||||
export const update = function (force = false) {
|
||||
if (!force) {
|
||||
const new_x = from.x + to.x;
|
||||
@ -64,8 +68,8 @@
|
||||
position.y={0.8}
|
||||
rotation.x={-Math.PI / 2}
|
||||
>
|
||||
<T.CircleGeometry args={[0.2, 16]} />
|
||||
<T.MeshBasicMaterial color={0x555555} />
|
||||
<T.CircleGeometry args={[0.3, 16]} />
|
||||
<T.MeshBasicMaterial {color} />
|
||||
</T.Mesh>
|
||||
|
||||
<T.Mesh
|
||||
@ -74,11 +78,11 @@
|
||||
position.y={0.8}
|
||||
rotation.x={-Math.PI / 2}
|
||||
>
|
||||
<T.CircleGeometry args={[0.2, 16]} />
|
||||
<T.MeshBasicMaterial color={0x555555} />
|
||||
<T.CircleGeometry args={[0.3, 16]} />
|
||||
<T.MeshBasicMaterial {color} />
|
||||
</T.Mesh>
|
||||
|
||||
<T.Mesh position.y={0.5} bind:ref={mesh}>
|
||||
<MeshLineGeometry {points} />
|
||||
<MeshLineMaterial width={2} attenuate={false} color={0x555555} />
|
||||
<MeshLineMaterial width={2} attenuate={false} {color} />
|
||||
</T.Mesh>
|
||||
|
@ -19,6 +19,7 @@
|
||||
selectedNodes,
|
||||
} from "./stores";
|
||||
import BoxSelection from "../BoxSelection.svelte";
|
||||
import type { OrbitControls } from "three/examples/jsm/Addons.js";
|
||||
|
||||
export let graph: GraphManager;
|
||||
setContext("graphManager", graph);
|
||||
@ -27,8 +28,9 @@
|
||||
const edges = graph.edges;
|
||||
|
||||
let camera: OrthographicCamera;
|
||||
const minZoom = 4;
|
||||
const maxZoom = 100;
|
||||
let controls: OrbitControls;
|
||||
const minZoom = 2;
|
||||
const maxZoom = 40;
|
||||
let mousePosition = [0, 0];
|
||||
let mouseDown: null | [number, number] = null;
|
||||
let boxSelection = false;
|
||||
@ -80,16 +82,16 @@
|
||||
}
|
||||
const node = graph.getNodeType(nodeTypeId);
|
||||
if (!node?.inputs) {
|
||||
return 2.5;
|
||||
return 5;
|
||||
}
|
||||
const height = 2.5 + 5 * Object.keys(node.inputs).length;
|
||||
const height = 5 + 10 * Object.keys(node.inputs).length;
|
||||
nodeHeightCache[nodeTypeId] = height;
|
||||
return height;
|
||||
}
|
||||
|
||||
setContext("isNodeInView", (node: NodeType) => {
|
||||
const height = getNodeHeight(node.type);
|
||||
const width = 10;
|
||||
const width = 20;
|
||||
return (
|
||||
// check x-axis
|
||||
node.position.x > cameraBounds[0] - width &&
|
||||
@ -159,14 +161,14 @@
|
||||
): [number, number] {
|
||||
if (typeof index === "number") {
|
||||
return [
|
||||
(node?.tmp?.x ?? node.position.x) + 10,
|
||||
(node?.tmp?.y ?? node.position.y) + 1.25 + 5 * index,
|
||||
(node?.tmp?.x ?? node.position.x) + 20,
|
||||
(node?.tmp?.y ?? node.position.y) + 2.5 + 10 * index,
|
||||
];
|
||||
} else {
|
||||
const _index = Object.keys(node.tmp?.type?.inputs || {}).indexOf(index);
|
||||
return [
|
||||
node?.tmp?.x ?? node.position.x,
|
||||
(node?.tmp?.y ?? node.position.y) + 5 + 5 * _index,
|
||||
(node?.tmp?.y ?? node.position.y) + 10 + 10 * _index,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -209,71 +211,74 @@
|
||||
|
||||
// handle box selection
|
||||
if (boxSelection) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const mouseD = projectScreenToWorld(mouseDown[0], mouseDown[1]);
|
||||
const x1 = Math.min(mouseD[0], mousePosition[0]);
|
||||
const x2 = Math.max(mouseD[0], mousePosition[0]);
|
||||
const y1 = Math.min(mouseD[1], mousePosition[1]);
|
||||
const y2 = Math.max(mouseD[1], mousePosition[1]);
|
||||
const _selectedNodes = $selectedNodes || new Set();
|
||||
for (const node of $nodes.values()) {
|
||||
if (!node?.tmp) continue;
|
||||
const x = node.position.x;
|
||||
const y = node.position.y;
|
||||
if (x > x1 && x < x2 && y > y1 && y < y2) {
|
||||
_selectedNodes.add(node.id);
|
||||
const height = getNodeHeight(node.type);
|
||||
if (x > x1 - 20 && x < x2 && y > y1 - height && y < y2) {
|
||||
$selectedNodes?.add(node.id);
|
||||
} else {
|
||||
_selectedNodes?.delete(node.id);
|
||||
$selectedNodes?.delete(node.id);
|
||||
}
|
||||
}
|
||||
$selectedNodes = _selectedNodes;
|
||||
$selectedNodes = $selectedNodes;
|
||||
return;
|
||||
}
|
||||
|
||||
// here we are handling dragging of nodes
|
||||
if ($activeNodeId === -1) return;
|
||||
if ($activeNodeId !== -1) {
|
||||
const node = graph.getNode($activeNodeId);
|
||||
if (!node || event.buttons !== 1) return;
|
||||
|
||||
const node = graph.getNode($activeNodeId);
|
||||
if (!node || event.buttons !== 1) return;
|
||||
node.tmp = node.tmp || {};
|
||||
|
||||
node.tmp = node.tmp || {};
|
||||
const oldX = node.tmp.downX || 0;
|
||||
const oldY = node.tmp.downY || 0;
|
||||
|
||||
const oldX = node.tmp.downX || 0;
|
||||
const oldY = node.tmp.downY || 0;
|
||||
let newX = oldX + (event.clientX - mouseDown[0]) / cameraPosition[2];
|
||||
let newY = oldY + (event.clientY - mouseDown[1]) / cameraPosition[2];
|
||||
|
||||
let newX = oldX + (event.clientX - mouseDown[0]) / cameraPosition[2];
|
||||
let newY = oldY + (event.clientY - mouseDown[1]) / cameraPosition[2];
|
||||
|
||||
if (event.ctrlKey) {
|
||||
const snapLevel = getSnapLevel();
|
||||
newX = snapToGrid(newX, 5 / snapLevel);
|
||||
newY = snapToGrid(newY, 5 / snapLevel);
|
||||
}
|
||||
|
||||
if (!node.tmp.isMoving) {
|
||||
const dist = Math.sqrt((oldX - newX) ** 2 + (oldY - newY) ** 2);
|
||||
if (dist > 0.2) {
|
||||
node.tmp.isMoving = true;
|
||||
if (event.ctrlKey) {
|
||||
const snapLevel = getSnapLevel();
|
||||
newX = snapToGrid(newX, 5 / snapLevel);
|
||||
newY = snapToGrid(newY, 5 / snapLevel);
|
||||
}
|
||||
}
|
||||
|
||||
const vecX = oldX - newX;
|
||||
const vecY = oldY - newY;
|
||||
|
||||
if ($selectedNodes?.size) {
|
||||
for (const nodeId of $selectedNodes) {
|
||||
const n = graph.getNode(nodeId);
|
||||
if (!n?.tmp) continue;
|
||||
n.tmp.x = (n?.tmp?.downX || 0) - vecX;
|
||||
n.tmp.y = (n?.tmp?.downY || 0) - vecY;
|
||||
updateNodePosition(n);
|
||||
if (!node.tmp.isMoving) {
|
||||
const dist = Math.sqrt((oldX - newX) ** 2 + (oldY - newY) ** 2);
|
||||
if (dist > 0.2) {
|
||||
node.tmp.isMoving = true;
|
||||
}
|
||||
}
|
||||
|
||||
const vecX = oldX - newX;
|
||||
const vecY = oldY - newY;
|
||||
|
||||
if ($selectedNodes?.size) {
|
||||
for (const nodeId of $selectedNodes) {
|
||||
const n = graph.getNode(nodeId);
|
||||
if (!n?.tmp) continue;
|
||||
n.tmp.x = (n?.tmp?.downX || 0) - vecX;
|
||||
n.tmp.y = (n?.tmp?.downY || 0) - vecY;
|
||||
updateNodePosition(n);
|
||||
}
|
||||
}
|
||||
|
||||
node.tmp.x = newX;
|
||||
node.tmp.y = newY;
|
||||
|
||||
updateNodePosition(node);
|
||||
|
||||
$edges = $edges;
|
||||
}
|
||||
|
||||
node.tmp.x = newX;
|
||||
node.tmp.y = newY;
|
||||
|
||||
updateNodePosition(node);
|
||||
|
||||
$edges = $edges;
|
||||
}
|
||||
|
||||
function handleMouseDown(event: MouseEvent) {
|
||||
@ -316,6 +321,7 @@
|
||||
}
|
||||
} else if (event.ctrlKey) {
|
||||
boxSelection = true;
|
||||
controls.enabled = false;
|
||||
} else {
|
||||
$activeNodeId = -1;
|
||||
$selectedNodes?.clear();
|
||||
@ -489,6 +495,7 @@
|
||||
}
|
||||
|
||||
mouseDown = null;
|
||||
controls.enabled = true;
|
||||
boxSelection = false;
|
||||
$activeSocket = null;
|
||||
$possibleSockets = [];
|
||||
@ -497,18 +504,24 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
<svelte:document
|
||||
on:mousemove={handleMouseMove}
|
||||
on:mouseup={handleMouseUp}
|
||||
on:mousedown={handleMouseDown}
|
||||
on:keydown={handleKeyDown}
|
||||
bind:innerWidth={width}
|
||||
bind:innerHeight={height}
|
||||
/>
|
||||
|
||||
<svelte:window bind:innerWidth={width} bind:innerHeight={height} />
|
||||
|
||||
<Debug />
|
||||
|
||||
<Camera bind:camera {maxZoom} {minZoom} bind:position={cameraPosition} />
|
||||
<Camera
|
||||
bind:controls
|
||||
bind:camera
|
||||
{maxZoom}
|
||||
{minZoom}
|
||||
bind:position={cameraPosition}
|
||||
/>
|
||||
|
||||
<Background {cameraPosition} {maxZoom} {minZoom} {width} {height} />
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import type { Edge as EdgeType, Node as NodeType, Socket } from "$lib/types";
|
||||
import type { Edge as EdgeType, Node as NodeType } from "$lib/types";
|
||||
import { HTML } from "@threlte/extras";
|
||||
import Edge from "../edges/Edge.svelte";
|
||||
import Node from "../Node.svelte";
|
||||
import { getContext, onMount } from "svelte";
|
||||
import type { Writable } from "svelte/store";
|
||||
import { activeSocket } from "./stores";
|
||||
import { activeSocket, colors } from "./stores";
|
||||
|
||||
export let nodes: Writable<Map<number, NodeType>>;
|
||||
export let edges: Writable<EdgeType[]>;
|
||||
@ -40,6 +40,7 @@
|
||||
{@const pos = getEdgePosition(edge)}
|
||||
{@const [x1, y1, x2, y2] = pos}
|
||||
<Edge
|
||||
color={$colors.backgroundColorLighter}
|
||||
from={{
|
||||
x: x1,
|
||||
y: y1,
|
||||
@ -56,9 +57,9 @@
|
||||
role="tree"
|
||||
tabindex="0"
|
||||
class="wrapper"
|
||||
class:zoom-small={cameraPosition[2] < 10}
|
||||
class:zoom-small={cameraPosition[2] < 2}
|
||||
class:hovering-sockets={activeSocket}
|
||||
style={`--cz: ${cameraPosition[2]}`}
|
||||
style={`--cz: ${cameraPosition[2]};`}
|
||||
>
|
||||
{#each $nodes.values() as node (node.id)}
|
||||
<Node {node} inView={cameraPosition && isNodeInView(node)} />
|
||||
@ -73,5 +74,6 @@
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
transform: scale(calc(var(--cz) * 0.1));
|
||||
--input-opacity: calc((var(--cz) - 2) / 5);
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,7 @@
|
||||
import type { Node, Socket } from "$lib/types";
|
||||
import { browser } from "$app/environment";
|
||||
import type { Socket } from "$lib/types";
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import { Color } from "three";
|
||||
|
||||
export const activeNodeId: Writable<number> = writable(-1);
|
||||
export const selectedNodes: Writable<Set<number> | null> = writable(null);
|
||||
@ -8,3 +10,41 @@ export const activeSocket: Writable<Socket | null> = writable(null);
|
||||
export const hoveredSocket: Writable<Socket | null> = writable(null);
|
||||
export const possibleSockets: Writable<Socket[]> = writable([]);
|
||||
export const possibleSocketIds: Writable<Set<string> | null> = writable(null);
|
||||
|
||||
|
||||
export const colors = writable({
|
||||
backgroundColorDarker: new Color().setStyle("#101010"),
|
||||
backgroundColor: new Color().setStyle("#151515"),
|
||||
backgroundColorLighter: new Color().setStyle("#202020")
|
||||
});
|
||||
|
||||
if (browser) {
|
||||
|
||||
const body = document.body;
|
||||
|
||||
function updateColors() {
|
||||
|
||||
const style = getComputedStyle(body);
|
||||
const backgroundColorDarker = style.getPropertyValue("--background-color-darker");
|
||||
const backgroundColor = style.getPropertyValue("--background-color");
|
||||
const backgroundColorLighter = style.getPropertyValue("--background-color-lighter");
|
||||
|
||||
colors.update(col => {
|
||||
col.backgroundColorDarker.setStyle(backgroundColorDarker);
|
||||
col.backgroundColor.setStyle(backgroundColor);
|
||||
col.backgroundColorLighter.setStyle(backgroundColorLighter);
|
||||
return col;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
globalThis["updateColors"] = updateColors;
|
||||
|
||||
body.addEventListener("transitionstart", () => {
|
||||
updateColors();
|
||||
})
|
||||
window.onload = () => {
|
||||
updateColors();
|
||||
}
|
||||
}
|
||||
|
17
frontend/src/lib/elements/Checkbox.story.svelte
Normal file
17
frontend/src/lib/elements/Checkbox.story.svelte
Normal file
@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import type { Hst } from "@histoire/plugin-svelte";
|
||||
export let Hst: Hst;
|
||||
import Checkbox from "./Checkbox.svelte";
|
||||
</script>
|
||||
|
||||
<Hst.Story>
|
||||
<div>
|
||||
<Checkbox checked={false} />
|
||||
</div>
|
||||
</Hst.Story>
|
||||
|
||||
<style>
|
||||
div {
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
58
frontend/src/lib/elements/Checkbox.svelte
Normal file
58
frontend/src/lib/elements/Checkbox.svelte
Normal file
@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
export let checked: boolean;
|
||||
</script>
|
||||
|
||||
<input type="checkbox" bind:checked />
|
||||
|
||||
<style>
|
||||
input[type="checkbox"] {
|
||||
/* Add if not using autoprefixer */
|
||||
-webkit-appearance: none;
|
||||
/* Remove most all native input styles */
|
||||
appearance: none;
|
||||
/* For iOS < 15 */
|
||||
background-color: var(--form-background);
|
||||
/* Not removed via appearance */
|
||||
margin: 0;
|
||||
|
||||
font: inherit;
|
||||
color: currentColor;
|
||||
width: 1.15em;
|
||||
height: 1.15em;
|
||||
border: 0.15em solid currentColor;
|
||||
border-radius: 0.15em;
|
||||
transform: translateY(-0.075em);
|
||||
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
|
||||
input[type="checkbox"]::before {
|
||||
content: "";
|
||||
width: 0.65em;
|
||||
height: 0.65em;
|
||||
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
|
||||
transform: scale(0);
|
||||
transform-origin: bottom left;
|
||||
transition: 120ms transform ease-in-out;
|
||||
box-shadow: inset 1em 1em var(--form-control-color);
|
||||
/* Windows High Contrast Mode */
|
||||
background-color: CanvasText;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked::before {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus {
|
||||
outline: max(2px, 0.15em) solid currentColor;
|
||||
outline-offset: max(2px, 0.15em);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled {
|
||||
--form-control-color: var(--form-control-disabled);
|
||||
|
||||
color: var(--form-control-disabled);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
0
frontend/src/lib/elements/Float.svelte
Normal file
0
frontend/src/lib/elements/Float.svelte
Normal file
0
frontend/src/lib/elements/Integer.svelte
Normal file
0
frontend/src/lib/elements/Integer.svelte
Normal file
0
frontend/src/lib/elements/Select.svelte
Normal file
0
frontend/src/lib/elements/Select.svelte
Normal file
@ -319,8 +319,8 @@ export class GraphManager {
|
||||
visible: false,
|
||||
},
|
||||
position: {
|
||||
x: x * 15,
|
||||
y: y * 20,
|
||||
x: x * 30,
|
||||
y: y * 40,
|
||||
},
|
||||
props: i == 0 ? { value: 0 } : {},
|
||||
type: i == 0 ? "input/float" : "math",
|
||||
@ -335,8 +335,8 @@ export class GraphManager {
|
||||
visible: false,
|
||||
},
|
||||
position: {
|
||||
x: width * 15,
|
||||
y: (height - 1) * 20,
|
||||
x: width * 30,
|
||||
y: (height - 1) * 40,
|
||||
},
|
||||
type: "output",
|
||||
props: {},
|
||||
|
@ -61,4 +61,12 @@ export function createNodePath({
|
||||
: ` H0`
|
||||
}
|
||||
Z`.replace(/\s+/g, " ");
|
||||
}
|
||||
}
|
||||
|
||||
export const debounce = (fn: Function, ms = 300) => {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
return function (this: any, ...args: any[]) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => fn.apply(this, args), ms);
|
||||
};
|
||||
};
|
||||
|
@ -37,7 +37,7 @@
|
||||
</div>
|
||||
|
||||
<div class="canvas-wrapper">
|
||||
<Canvas shadows={false} renderMode="on-demand" autoRender={true}>
|
||||
<Canvas shadows={false} renderMode="on-demand" colorManagementEnabled={false}>
|
||||
<!-- <PerfMonitor /> -->
|
||||
<Graph {graph} bind:debug />
|
||||
</Canvas>
|
||||
|
@ -23,28 +23,6 @@
|
||||
:root {
|
||||
font-family: 'Fira Code', monospace;
|
||||
|
||||
/* Colors */
|
||||
--primary-color: #007bff;
|
||||
/* Primary brand color */
|
||||
--secondary-color: #6c757d;
|
||||
/* Secondary color */
|
||||
--background-color: #151515;
|
||||
--background-color-lightest: #ffffff;
|
||||
--background-color-lighter: #202020;
|
||||
--background-color-dark: #dae0e5;
|
||||
--background-color-darkest: #c8d1d7;
|
||||
/* Background color */
|
||||
--text-color: #aeaeae;
|
||||
/* Text color */
|
||||
--accent-color: #ffc107;
|
||||
/* Accent color */
|
||||
|
||||
/* Typography */
|
||||
--font-family: Arial, sans-serif;
|
||||
--font-size-base: 16px;
|
||||
/* Base font size */
|
||||
--line-height-base: 1.5;
|
||||
/* Base line height */
|
||||
|
||||
/* Spacing */
|
||||
--spacing-xs: 4px;
|
||||
@ -62,4 +40,23 @@
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
|
||||
/* Secondary color */
|
||||
--secondary-color: #6c757d;
|
||||
/* Background color */
|
||||
--background-color-lighter: #202020;
|
||||
--background-color: #151515;
|
||||
--background-color-darker: #101010;
|
||||
--text-color: #aeaeae;
|
||||
}
|
||||
|
||||
body.theme-catppuccin {
|
||||
--text-color: #CDD6F4;
|
||||
--background-color-lighter: #313244;
|
||||
--background-color: #1E1E2E;
|
||||
--background-color-darker: #11111b;
|
||||
}
|
||||
|
||||
/* canvas { */
|
||||
/* display: none !important; */
|
||||
/* } */
|
||||
|
Loading…
Reference in New Issue
Block a user