mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 12:08:12 +08:00
Move errors to popup, remove tooltips
This commit is contained in:
@@ -180,10 +180,10 @@
|
||||
return `Data Type: ${value.resolvedType}`;
|
||||
}
|
||||
|
||||
function validTypesText(value: FrontendGraphInput): string {
|
||||
const validTypes = value.validTypes.length > 0 ? value.validTypes.map((x) => `• ${x}`).join("\n") : "None";
|
||||
return `Valid Types:\n${validTypes}`;
|
||||
}
|
||||
// function validTypesText(value: FrontendGraphInput): string {
|
||||
// const validTypes = value.validTypes.length > 0 ? value.validTypes.map((x) => `• ${x}`).join("\n") : "None";
|
||||
// return `Valid Types:\n${validTypes}`;
|
||||
// }
|
||||
|
||||
function outputConnectedToText(output: FrontendGraphOutput): string {
|
||||
if (output.connectedTo.length === 0) return "Connected to nothing";
|
||||
@@ -257,6 +257,27 @@
|
||||
</LayoutCol>
|
||||
{/if}
|
||||
|
||||
{#if $nodeGraph.error}
|
||||
<div class="node-error-container" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}>
|
||||
<span
|
||||
class="node-error faded"
|
||||
style={`left: ${$nodeGraph.error.position.x}px;
|
||||
top: ${$nodeGraph.error.position.y}px;`}
|
||||
transition:fade={FADE_TRANSITION}
|
||||
title=""
|
||||
data-node-error>{$nodeGraph.error.error}</span
|
||||
>
|
||||
<span
|
||||
class="node-error hover"
|
||||
style={`left: ${$nodeGraph.error.position.x}px;
|
||||
top: ${$nodeGraph.error.position.y}px;`}
|
||||
transition:fade={FADE_TRANSITION}
|
||||
title=""
|
||||
data-node-error>{$nodeGraph.error.error}</span
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Click target debug visualizations -->
|
||||
{#if $nodeGraph.clickTargets}
|
||||
<div class="click-targets" style:transform-origin="0 0" style:transform={`translate(${$nodeGraph.transform.x}px, ${$nodeGraph.transform.y}px) scale(${$nodeGraph.transform.scale})`}>
|
||||
@@ -492,7 +513,6 @@
|
||||
{@const layerAreaWidth = $nodeGraph.layerWidths.get(node.id) || 8}
|
||||
{@const layerChainWidth = $nodeGraph.chainWidths.get(node.id) || 0}
|
||||
{@const hasLeftInputWire = $nodeGraph.hasLeftInputWire.get(node.id) || false}
|
||||
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
||||
<div
|
||||
class="layer"
|
||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||
@@ -506,13 +526,8 @@
|
||||
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
||||
style:--layer-area-width={layerAreaWidth}
|
||||
style:--node-chain-area-left-extension={layerChainWidth !== 0 ? layerChainWidth + 0.5 : 0}
|
||||
title={`${node.displayName}\n\n${description || ""}`.trim() + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")}
|
||||
data-node={node.id}
|
||||
>
|
||||
{#if node.errors}
|
||||
<span class="node-error faded" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||
<span class="node-error hover" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||
{/if}
|
||||
<div class="thumbnail">
|
||||
{#if $nodeGraph.thumbnails.has(node.id)}
|
||||
{@html $nodeGraph.thumbnails.get(node.id)}
|
||||
@@ -528,7 +543,6 @@
|
||||
style:--data-color={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
||||
{#if node.primaryOutput.connectedTo.length > 0}
|
||||
<path d="M0,6.953l2.521,-1.694a2.649,2.649,0,0,1,2.959,0l2.52,1.694v5.047h-8z" fill="var(--data-color)" />
|
||||
{#if node.primaryOutputConnectedToLayer}
|
||||
@@ -549,9 +563,6 @@
|
||||
style:--data-color={`var(--color-data-${(node.primaryInput?.dataType || "General").toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${(node.primaryInput?.dataType || "General").toLowerCase()}-dim)`}
|
||||
>
|
||||
{#if node.primaryInput}
|
||||
<title>{`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`}</title>
|
||||
{/if}
|
||||
{#if node.primaryInput?.connectedTo !== "nothing"}
|
||||
<path d="M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z" fill="var(--data-color)" />
|
||||
{#if node.primaryInputConnectedToLayer}
|
||||
@@ -574,7 +585,6 @@
|
||||
style:--data-color={`var(--color-data-${stackDataInput.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${stackDataInput.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(stackDataInput)}\n\n${validTypesText(stackDataInput)}\n\n${inputConnectedToText(stackDataInput)}`}</title>
|
||||
{#if stackDataInput.connectedTo !== undefined}
|
||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||
{:else}
|
||||
@@ -587,7 +597,7 @@
|
||||
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
|
||||
<TextLabel>{node.displayName}</TextLabel>
|
||||
</div>
|
||||
<div class="solo-drag-grip" title="Drag only this layer without pushing others outside the stack"></div>
|
||||
<div class="solo-drag-grip" />
|
||||
<IconButton
|
||||
class="visibility"
|
||||
data-visibility-button
|
||||
@@ -644,7 +654,6 @@
|
||||
.map(([_, node], nodeIndex) => ({ node, nodeIndex })) as { node, nodeIndex } (nodeIndex)}
|
||||
{@const exposedInputsOutputs = zipWithUndefined(node.exposedInputs, node.exposedOutputs)}
|
||||
{@const clipPathId = String(Math.random()).substring(2)}
|
||||
{@const description = (node.reference && $nodeGraph.nodeDescriptions.get(node.reference)) || undefined}
|
||||
<div
|
||||
class="node"
|
||||
class:selected={$nodeGraph.selected.includes(node.id)}
|
||||
@@ -655,13 +664,8 @@
|
||||
style:--clip-path-id={`url(#${clipPathId})`}
|
||||
style:--data-color={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${(node.primaryOutput?.dataType || "General").toLowerCase()}-dim)`}
|
||||
title={`${node.displayName}\n\n${description || ""}`.trim() + (editor.handle.inDevelopmentMode() ? `\n\nNode ID: ${node.id}` : "")}
|
||||
data-node={node.id}
|
||||
>
|
||||
{#if node.errors}
|
||||
<span class="node-error faded" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||
<span class="node-error hover" transition:fade={FADE_TRANSITION} title="" data-node-error>{node.errors}</span>
|
||||
{/if}
|
||||
<!-- Primary row -->
|
||||
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
|
||||
<IconLabel icon={nodeIcon(node.reference)} />
|
||||
@@ -673,7 +677,7 @@
|
||||
<div class="secondary" class:in-selected-network={$nodeGraph.inSelectedNetwork}>
|
||||
{#each exposedInputsOutputs as [input, output]}
|
||||
<div class={`secondary-row expanded ${input !== undefined ? "input" : "output"}`}>
|
||||
<TextLabel tooltip={(input !== undefined ? `${input.name}\n\n${input.description}` : `${output.name}\n\n${output.description}`).trim()}>
|
||||
<TextLabel>
|
||||
{input !== undefined ? input.name : output.name}
|
||||
</TextLabel>
|
||||
</div>
|
||||
@@ -692,7 +696,6 @@
|
||||
style:--data-color={`var(--color-data-${node.primaryInput.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${node.primaryInput.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(node.primaryInput)}\n\n${validTypesText(node.primaryInput)}\n\n${inputConnectedToText(node.primaryInput)}`}</title>
|
||||
{#if node.primaryInput.connectedTo !== undefined}
|
||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||
{:else}
|
||||
@@ -711,7 +714,6 @@
|
||||
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(secondary)}\n\n${validTypesText(secondary)}\n\n${inputConnectedToText(secondary)}`}</title>
|
||||
{#if secondary.connectedTo !== undefined}
|
||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||
{:else}
|
||||
@@ -733,7 +735,6 @@
|
||||
style:--data-color={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${node.primaryOutput.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(node.primaryOutput)}\n\n${outputConnectedToText(node.primaryOutput)}`}</title>
|
||||
{#if node.primaryOutput.connectedTo !== undefined}
|
||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||
{:else}
|
||||
@@ -751,7 +752,6 @@
|
||||
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}
|
||||
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
|
||||
>
|
||||
<title>{`${dataTypeTooltip(secondary)}\n\n${outputConnectedToText(secondary)}`}</title>
|
||||
{#if secondary.connectedTo !== undefined}
|
||||
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
|
||||
{:else}
|
||||
@@ -776,7 +776,6 @@
|
||||
</div>
|
||||
|
||||
<!-- Box selection widget -->
|
||||
<!-- TODO: Make its initial corner stay put (in graph space) when panning around -->
|
||||
{#if $nodeGraph.box}
|
||||
<div
|
||||
class="box-selection"
|
||||
@@ -838,6 +837,72 @@
|
||||
}
|
||||
}
|
||||
|
||||
.node-error-container {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
||||
.node-error {
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
white-space: pre-wrap;
|
||||
max-width: 600px;
|
||||
line-height: 18px;
|
||||
color: var(--color-2-mildblack);
|
||||
background: var(--color-error-red);
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
transition: opacity 0.2s;
|
||||
opacity: 0.5;
|
||||
transform: translateY(-100%);
|
||||
|
||||
// Tail
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
bottom: -8px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 0 6px;
|
||||
border-color: var(--color-error-red) transparent transparent transparent;
|
||||
}
|
||||
|
||||
&.hover {
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&.faded:hover + .hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.faded:hover {
|
||||
z-index: 2;
|
||||
opacity: 1;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
transition:
|
||||
opacity 0.2s,
|
||||
z-index 0s 0.2s;
|
||||
|
||||
&::selection {
|
||||
background-color: var(--color-e-nearwhite);
|
||||
|
||||
// Target only Safari
|
||||
@supports (background: -webkit-named-image(i)) {
|
||||
& {
|
||||
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
|
||||
// https://stackoverflow.com/a/71753552/775283
|
||||
background-color: rgba(var(--color-e-nearwhite-rgb), calc(254 / 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.click-targets {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
@@ -1017,68 +1082,6 @@
|
||||
// backdrop-filter: blur(4px);
|
||||
background: rgba(var(--color-0-black-rgb), 0.33);
|
||||
|
||||
.node-error {
|
||||
position: absolute;
|
||||
width: max-content;
|
||||
white-space: pre-wrap;
|
||||
max-width: 600px;
|
||||
line-height: 18px;
|
||||
color: var(--color-2-mildblack);
|
||||
background: var(--color-error-red);
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
bottom: calc(100% + 12px);
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
opacity: 0.5;
|
||||
|
||||
// Tail
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
bottom: -8px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 8px 6px 0 6px;
|
||||
border-color: var(--color-error-red) transparent transparent transparent;
|
||||
}
|
||||
|
||||
&.hover {
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&.faded:hover + .hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.faded:hover {
|
||||
z-index: 2;
|
||||
opacity: 1;
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
transition:
|
||||
opacity 0.2s,
|
||||
z-index 0s 0.2s;
|
||||
|
||||
&::selection {
|
||||
background-color: var(--color-e-nearwhite);
|
||||
|
||||
// Target only Safari
|
||||
@supports (background: -webkit-named-image(i)) {
|
||||
& {
|
||||
// Setting an alpha value opts out of Safari's "fancy" (but not visible on dark backgrounds) selection highlight rendering
|
||||
// https://stackoverflow.com/a/71753552/775283
|
||||
background-color: rgba(var(--color-e-nearwhite-rgb), calc(254 / 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
||||
@@ -35,7 +35,7 @@ export class UpdateClickTargets extends JsMessage {
|
||||
|
||||
const ContextTupleToVec2 = Transform((data) => {
|
||||
if (data.obj.contextMenuInformation === undefined) return undefined;
|
||||
const contextMenuCoordinates = { x: data.obj.contextMenuInformation.contextMenuCoordinates[0], y: data.obj.contextMenuInformation.contextMenuCoordinates[1] };
|
||||
const contextMenuCoordinates = data.obj.contextMenuInformation.contextMenuCoordinates;
|
||||
let contextMenuData = data.obj.contextMenuInformation.contextMenuData;
|
||||
if (contextMenuData.ToggleLayer !== undefined) {
|
||||
contextMenuData = { nodeId: contextMenuData.ToggleLayer.nodeId, currentlyIsNode: contextMenuData.ToggleLayer.currentlyIsNode };
|
||||
@@ -94,6 +94,15 @@ export class UpdateNodeGraphNodes extends JsMessage {
|
||||
readonly nodes!: FrontendNode[];
|
||||
}
|
||||
|
||||
export class UpdateNodeGraphError extends JsMessage {
|
||||
readonly error!: NodeGraphError | undefined;
|
||||
}
|
||||
|
||||
export class NodeGraphError {
|
||||
readonly position!: XY;
|
||||
readonly error!: string;
|
||||
}
|
||||
|
||||
export class UpdateVisibleNodes extends JsMessage {
|
||||
readonly nodes!: bigint[];
|
||||
}
|
||||
@@ -1691,6 +1700,7 @@ export const messageMakers: Record<string, MessageMaker> = {
|
||||
UpdateMouseCursor,
|
||||
UpdateNodeGraphControlBarLayout,
|
||||
UpdateNodeGraphNodes,
|
||||
UpdateNodeGraphError,
|
||||
UpdateNodeGraphSelection,
|
||||
UpdateNodeGraphTransform,
|
||||
UpdateNodeGraphWires,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import { type Editor } from "@graphite/editor";
|
||||
import type { NodeGraphError } from "@graphite/messages";
|
||||
import {
|
||||
type Box,
|
||||
type FrontendClickTargets,
|
||||
@@ -25,6 +26,7 @@ import {
|
||||
UpdateNodeGraphTransform,
|
||||
UpdateNodeThumbnail,
|
||||
UpdateWirePathInProgress,
|
||||
UpdateNodeGraphError,
|
||||
} from "@graphite/messages";
|
||||
|
||||
export function createNodeGraphState(editor: Editor) {
|
||||
@@ -32,6 +34,7 @@ export function createNodeGraphState(editor: Editor) {
|
||||
box: undefined as Box | undefined,
|
||||
clickTargets: undefined as FrontendClickTargets | undefined,
|
||||
contextMenuInformation: undefined as ContextMenuInformation | undefined,
|
||||
error: undefined as NodeGraphError | undefined,
|
||||
layerWidths: new Map<bigint, number>(),
|
||||
chainWidths: new Map<bigint, number>(),
|
||||
hasLeftInputWire: new Map<bigint, boolean>(),
|
||||
@@ -118,6 +121,12 @@ export function createNodeGraphState(editor: Editor) {
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphError, (updateNodeGraphError) => {
|
||||
update((state) => {
|
||||
state.error = updateNodeGraphError.error;
|
||||
return state;
|
||||
});
|
||||
});
|
||||
editor.subscriptions.subscribeJsMessage(UpdateVisibleNodes, (updateVisibleNodes) => {
|
||||
update((state) => {
|
||||
state.visibleNodes = new Set<bigint>(updateVisibleNodes.nodes);
|
||||
|
||||
Reference in New Issue
Block a user