blob: d19ce38883034e606d8b55119eeb49650decff90 [file]
// Copyright (C) 2025 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
.pf-canvas {
height: 100%;
overflow: hidden;
background: linear-gradient(
0deg,
var(--pf-color-border-secondary) 1px,
transparent 1px
),
linear-gradient(
90deg,
var(--pf-color-border-secondary) 1px,
transparent 1px
);
background-size: 20px 20px;
background-color: var(--pf-color-background);
position: relative;
user-select: none;
font-family: var(--pf-font-compact);
cursor: grab;
}
.pf-canvas-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: visible;
}
.pf-nodegraph-controls {
position: absolute;
top: 16px;
right: 16px;
z-index: 100;
pointer-events: auto;
display: flex;
gap: 8px;
}
.pf-node {
position: absolute;
background: var(--pf-color-background-secondary);
border: 2px solid var(--pf-color-border);
border-radius: 8px;
min-width: 180px;
box-shadow: 0 4px 12px var(--pf-color-box-shadow);
cursor: move;
pointer-events: auto;
padding-block: 12px;
}
// Wrapper for dock chains - uses flexbox to make children same width
.pf-dock-chain {
position: absolute;
display: flex;
flex-direction: column;
pointer-events: auto;
box-shadow: 0 4px 12px var(--pf-color-box-shadow);
// All nodes in chain stretch to same width (determined by widest node)
.pf-node {
width: 100%;
position: relative !important;
left: auto !important;
top: auto !important;
box-shadow: none; // No box shadow for docked nodes
}
}
.pf-node.pf-selected {
border-color: var(--pf-color-accent);
box-shadow: 0 0 0 2px
color-mix(in srgb, var(--pf-color-accent) 30%, transparent);
z-index: 1; // Make sure box shadow appears above other nodes
}
// Docked child: flush top edge with no rounded corners or border
.pf-node.pf-docked-child {
border-top-left-radius: 0;
border-top-right-radius: 0;
margin-top: -2px; // Overlap border with parent
}
// Parent with docked child: flush bottom edge with no rounded corners
.pf-node.pf-has-docked-child {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
// Dock target highlight with pulsing animation
.pf-node.pf-dock-target {
box-shadow: 0 4px 0 3px var(--pf-color-accent);
animation: pulse-dock 0.6s ease-in-out infinite;
}
@keyframes pulse-dock {
0%,
100% {
box-shadow: 0 4px 0 3px var(--pf-color-accent);
}
50% {
box-shadow: 0 6px 0 5px var(--pf-color-accent);
opacity: 0.95;
}
}
.pf-node-header {
background: var(--pf-color-background);
padding: 8px 12px;
border-radius: 6px 6px 0 0;
color: var(--pf-color-text);
font-weight: bold;
font-size: 14px;
border-bottom: 1px solid var(--pf-color-border);
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
}
.pf-node-title {
flex: 1;
}
.pf-node-content {
padding-inline: 12px;
}
.pf-port-row {
position: relative;
margin: 8px 0;
color: var(--pf-color-text-muted);
font-size: 13px;
padding: 4px 16px;
.pf-port {
transform: translateY(-50%);
}
}
.pf-port-input {
text-align: left;
}
.pf-port-output {
text-align: right;
}
.pf-port {
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--pf-color-border);
border: 2px solid var(--pf-color-border-secondary);
cursor: crosshair;
position: absolute;
top: 50%;
z-index: 10;
}
.pf-output:hover {
background: var(--pf-color-accent);
border-color: var(--pf-color-accent);
}
.pf-port.pf-connected {
background: var(--pf-color-accent);
border-color: var(--pf-color-accent);
}
.pf-port.pf-input {
left: -8px;
}
.pf-port.pf-port-top {
top: 0;
left: 50%;
transform: translateY(-50%);
}
.pf-port.pf-port-bottom {
top: unset;
bottom: 0;
left: 50%;
transform: translateY(50%);
}
.pf-port.pf-output {
right: -8px;
}
svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
overflow: visible;
}
.pf-connection {
stroke: var(--pf-color-accent);
stroke-width: 2;
fill: none;
filter: drop-shadow(
0 0 4px color-mix(in srgb, var(--pf-color-accent) 50%, transparent)
);
transition:
stroke-width 0.2s,
stroke 0.2s;
}
.pf-connection:hover {
stroke: var(--pf-color-danger);
stroke-width: 3;
filter: drop-shadow(
0 0 6px color-mix(in srgb, var(--pf-color-danger) 80%, transparent)
);
}
.pf-temp-connection {
stroke: var(--pf-color-text-muted);
stroke-width: 2;
fill: none;
stroke-dasharray: 5, 5;
}
.pf-connecting {
cursor: crosshair;
.pf-input:hover {
background: var(--pf-color-accent);
border-color: var(--pf-color-accent);
cursor: copy;
}
.pf-output:hover {
background: var(--pf-color-border);
border-color: var(--pf-color-border-secondary);
cursor: not-allowed;
}
}
.pf-output.pf-active,
.pf-output.pf-active:hover {
background: var(--pf-color-accent);
border-color: var(--pf-color-accent);
cursor: crosshair;
}
.pf-panning {
cursor: grabbing;
}