@hlang-tech/editor-ui 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +78 -2
- package/lib/canvas/CanvasChrome.css +45 -0
- package/lib/canvas/CanvasDock.css +82 -0
- package/lib/canvas/EmptyState.css +23 -0
- package/lib/command-palette/NodeSearch.css +153 -0
- package/lib/context-menu/NodeContextMenu.css +102 -0
- package/lib/edges/FlowEdge.css +80 -0
- package/lib/index.d.mts +971 -0
- package/lib/index.d.ts +971 -0
- package/lib/index.js +2402 -0
- package/lib/index.js.map +1 -0
- package/lib/index.mjs +2318 -0
- package/lib/index.mjs.map +1 -0
- package/lib/nodes/AssetNode.css +146 -0
- package/lib/nodes/HlangNode.css +192 -0
- package/lib/nodes/PillNode.css +185 -0
- package/lib/overlays/Cheatsheet.css +107 -0
- package/lib/overlays/Toast.css +34 -0
- package/lib/panels/AssetGrid.css +38 -0
- package/lib/panels/InspectorPanel.css +161 -0
- package/lib/panels/OutlineTree.css +208 -0
- package/lib/panels/ParamForm.css +88 -0
- package/lib/panels/PositionPanel.css +87 -0
- package/lib/panels/PreviewPanel.css +51 -0
- package/lib/panels/RailTabs.css +34 -0
- package/lib/shell/EditorShell.css +75 -0
- package/lib/styles.css +33 -0
- package/lib/tokens/tokens.css +100 -0
- package/lib/toolbar/ToolCluster.css +48 -0
- package/lib/toolbar/Toolbar.css +126 -0
- package/package.json +97 -4
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
.hl-inspector {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 18px;
|
|
5
|
+
padding: 14px;
|
|
6
|
+
height: 100%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.hl-inspector-empty {
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
}
|
|
13
|
+
.hl-inspector-hint {
|
|
14
|
+
margin: 0;
|
|
15
|
+
font-size: 12px;
|
|
16
|
+
color: var(--hl-ink-3);
|
|
17
|
+
text-align: center;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hl-inspector-head {
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: flex-start;
|
|
23
|
+
gap: 9px;
|
|
24
|
+
padding-bottom: 14px;
|
|
25
|
+
border-bottom: 1px solid var(--hl-line);
|
|
26
|
+
}
|
|
27
|
+
.hl-inspector-kind {
|
|
28
|
+
--hl-kind: var(--hl-silver);
|
|
29
|
+
font-size: 10px;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
color: var(--hl-void);
|
|
32
|
+
background: var(--hl-kind);
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
padding: 2px 6px;
|
|
35
|
+
line-height: 1.5;
|
|
36
|
+
}
|
|
37
|
+
.hl-inspector-kind.hl-r { --hl-kind: var(--hl-r); }
|
|
38
|
+
.hl-inspector-kind.hl-t { --hl-kind: var(--hl-t); }
|
|
39
|
+
.hl-inspector-kind.hl-w { --hl-kind: var(--hl-w); }
|
|
40
|
+
.hl-inspector-titles {
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
gap: 2px;
|
|
44
|
+
min-width: 0;
|
|
45
|
+
}
|
|
46
|
+
.hl-inspector-name {
|
|
47
|
+
font-size: 14px;
|
|
48
|
+
font-weight: 600;
|
|
49
|
+
letter-spacing: -0.01em;
|
|
50
|
+
color: var(--hl-ink);
|
|
51
|
+
}
|
|
52
|
+
.hl-inspector-role {
|
|
53
|
+
font-size: 10.5px;
|
|
54
|
+
color: var(--hl-ink-3);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.hl-inspector-section {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
gap: 10px;
|
|
61
|
+
}
|
|
62
|
+
.hl-inspector-section-title {
|
|
63
|
+
margin: 0;
|
|
64
|
+
font-size: 10px;
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
text-transform: uppercase;
|
|
67
|
+
letter-spacing: 0.14em;
|
|
68
|
+
color: var(--hl-ink-3);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.hl-inspector-ports {
|
|
72
|
+
list-style: none;
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding: 0;
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
gap: 6px;
|
|
78
|
+
}
|
|
79
|
+
.hl-inspector-port {
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
gap: 8px;
|
|
83
|
+
font-size: 12px;
|
|
84
|
+
color: var(--hl-ink-2);
|
|
85
|
+
}
|
|
86
|
+
.hl-inspector-port.is-error {
|
|
87
|
+
color: color-mix(in srgb, var(--hl-error) 80%, var(--hl-ink-2));
|
|
88
|
+
}
|
|
89
|
+
.hl-port-dot {
|
|
90
|
+
width: 7px;
|
|
91
|
+
height: 7px;
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
}
|
|
95
|
+
.hl-dir-i { background: var(--hl-ink-3); }
|
|
96
|
+
.hl-dir-o { background: var(--hl-silver); }
|
|
97
|
+
.hl-inspector-port.is-error .hl-port-dot { background: var(--hl-error); }
|
|
98
|
+
.hl-inspector-port-dir {
|
|
99
|
+
margin-left: auto;
|
|
100
|
+
font-size: 10px;
|
|
101
|
+
color: var(--hl-ink-3);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Header preview thumbnail — image for assets, kind medallion otherwise. */
|
|
105
|
+
.hl-inspector-preview {
|
|
106
|
+
--hl-kind: var(--hl-silver);
|
|
107
|
+
height: 132px;
|
|
108
|
+
border-radius: var(--hl-r-md);
|
|
109
|
+
overflow: hidden;
|
|
110
|
+
display: grid;
|
|
111
|
+
place-items: center;
|
|
112
|
+
background: linear-gradient(135deg,
|
|
113
|
+
color-mix(in oklab, var(--hl-kind) 22%, var(--hl-surface-2)),
|
|
114
|
+
var(--hl-void-2));
|
|
115
|
+
box-shadow: var(--hl-glass-edge);
|
|
116
|
+
}
|
|
117
|
+
.hl-inspector-preview.hl-r { --hl-kind: var(--hl-r); }
|
|
118
|
+
.hl-inspector-preview.hl-t { --hl-kind: var(--hl-t); }
|
|
119
|
+
.hl-inspector-preview.hl-w { --hl-kind: var(--hl-w); }
|
|
120
|
+
.hl-inspector-preview-img {
|
|
121
|
+
width: 100%;
|
|
122
|
+
height: 100%;
|
|
123
|
+
object-fit: cover;
|
|
124
|
+
}
|
|
125
|
+
.hl-inspector-preview-badge {
|
|
126
|
+
width: 42px;
|
|
127
|
+
height: 42px;
|
|
128
|
+
display: grid;
|
|
129
|
+
place-items: center;
|
|
130
|
+
border-radius: 12px;
|
|
131
|
+
background: radial-gradient(circle at 32% 28%,
|
|
132
|
+
color-mix(in oklab, var(--hl-kind) 85%, white), var(--hl-kind) 75%);
|
|
133
|
+
color: var(--hl-void);
|
|
134
|
+
font-size: 17px;
|
|
135
|
+
font-weight: 700;
|
|
136
|
+
box-shadow: 0 0 18px -4px var(--hl-kind), var(--hl-glass-edge-hi);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Redesigned empty state — the first impression when nothing is selected. */
|
|
140
|
+
.hl-inspector-blank {
|
|
141
|
+
display: flex;
|
|
142
|
+
flex-direction: column;
|
|
143
|
+
align-items: center;
|
|
144
|
+
gap: 10px;
|
|
145
|
+
text-align: center;
|
|
146
|
+
padding: 0 8px;
|
|
147
|
+
}
|
|
148
|
+
.hl-inspector-blank-badge {
|
|
149
|
+
width: 34px;
|
|
150
|
+
height: 34px;
|
|
151
|
+
border-radius: 10px;
|
|
152
|
+
background: radial-gradient(circle at 30% 25%, var(--hl-silver-hi), var(--hl-silver-lo) 72%);
|
|
153
|
+
box-shadow: 0 0 16px -4px var(--hl-silver), var(--hl-glass-edge-hi);
|
|
154
|
+
opacity: 0.5;
|
|
155
|
+
}
|
|
156
|
+
.hl-inspector-blank-title {
|
|
157
|
+
margin: 0;
|
|
158
|
+
font-size: 13px;
|
|
159
|
+
font-weight: 600;
|
|
160
|
+
color: var(--hl-ink-2);
|
|
161
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OutlineTree — a nested layer tree. Group heads (topology sub-flows) expand to
|
|
3
|
+
* member rows. Per-type icons, hover-revealed visible/lock controls, and a
|
|
4
|
+
* solid silver highlight on the selected row.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
.hl-outline {
|
|
8
|
+
padding: 2px 10px 10px;
|
|
9
|
+
overflow-y: auto;
|
|
10
|
+
min-height: 0;
|
|
11
|
+
}
|
|
12
|
+
.hl-outline-empty {
|
|
13
|
+
padding: 12px;
|
|
14
|
+
font-size: 11px;
|
|
15
|
+
color: var(--hl-ink-3);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Group header (a sub-flow). */
|
|
19
|
+
.hl-outline-grouphead {
|
|
20
|
+
width: 100%;
|
|
21
|
+
display: flex;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: 6px;
|
|
24
|
+
padding: 6px 8px;
|
|
25
|
+
border: none;
|
|
26
|
+
background: transparent;
|
|
27
|
+
color: var(--hl-ink-2);
|
|
28
|
+
font-family: var(--hl-font-ui);
|
|
29
|
+
font-size: 11px;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
letter-spacing: 0.02em;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
border-radius: var(--hl-r-sm);
|
|
34
|
+
transition: background 0.14s var(--hl-ease), color 0.14s var(--hl-ease);
|
|
35
|
+
}
|
|
36
|
+
.hl-outline-grouphead:hover {
|
|
37
|
+
background: rgba(255, 255, 255, 0.04);
|
|
38
|
+
color: var(--hl-ink);
|
|
39
|
+
}
|
|
40
|
+
.hl-outline-caret {
|
|
41
|
+
font-size: 9px;
|
|
42
|
+
color: var(--hl-ink-3);
|
|
43
|
+
transition: transform 0.16s var(--hl-ease);
|
|
44
|
+
}
|
|
45
|
+
.hl-outline-caret.is-open {
|
|
46
|
+
transform: rotate(90deg);
|
|
47
|
+
}
|
|
48
|
+
.hl-outline-groupname {
|
|
49
|
+
flex: 1;
|
|
50
|
+
text-align: left;
|
|
51
|
+
}
|
|
52
|
+
.hl-outline-count {
|
|
53
|
+
font-size: 10px;
|
|
54
|
+
color: var(--hl-ink-3);
|
|
55
|
+
background: rgba(255, 255, 255, 0.05);
|
|
56
|
+
border-radius: var(--hl-r-pill);
|
|
57
|
+
padding: 0 7px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Members of a Flow are a FLAT list, NOT a tree. hlang's graph is a DAG — the
|
|
61
|
+
nodes in a weakly-connected component are peers, and their real relationships
|
|
62
|
+
(edges, fan-in/out, feedback) live on the canvas, not here. So the outline
|
|
63
|
+
only expresses GROUPING (which Flow a node belongs to), with no parent/child
|
|
64
|
+
guide line or nesting indent that would imply a hierarchy that doesn't exist.
|
|
65
|
+
A small left inset just visually associates members with their group header. */
|
|
66
|
+
.hl-outline-members {
|
|
67
|
+
list-style: none;
|
|
68
|
+
margin: 0 0 4px;
|
|
69
|
+
padding: 0 0 0 8px;
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
gap: 2px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.hl-outline-row {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
border-radius: var(--hl-r-sm);
|
|
79
|
+
transition: background 0.14s var(--hl-ease);
|
|
80
|
+
}
|
|
81
|
+
.hl-outline-row:hover {
|
|
82
|
+
background: rgba(255, 255, 255, 0.05);
|
|
83
|
+
}
|
|
84
|
+
/* Solid silver highlight when selected — full row, not a thin border. */
|
|
85
|
+
.hl-outline-row.is-active {
|
|
86
|
+
background: linear-gradient(90deg,
|
|
87
|
+
color-mix(in oklab, var(--hl-silver) 26%, transparent),
|
|
88
|
+
color-mix(in oklab, var(--hl-silver) 14%, transparent));
|
|
89
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--hl-silver) 30%, transparent);
|
|
90
|
+
}
|
|
91
|
+
/* A hidden layer must stay READABLE, not vanish. Dim only the NAME (one step,
|
|
92
|
+
not 0.4 on the whole row) and let the persistent slash-eye badge carry the
|
|
93
|
+
state. Icon, controls, and selection highlight keep full contrast. */
|
|
94
|
+
.hl-outline-row.is-hidden .hl-outline-name {
|
|
95
|
+
color: var(--hl-ink-3);
|
|
96
|
+
font-style: italic;
|
|
97
|
+
}
|
|
98
|
+
.hl-outline-row.is-hidden .hl-outline-icon {
|
|
99
|
+
opacity: 0.55;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.hl-outline-main {
|
|
103
|
+
flex: 1;
|
|
104
|
+
min-width: 0;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 9px;
|
|
108
|
+
padding: 6px 6px 6px 8px;
|
|
109
|
+
border: none;
|
|
110
|
+
background: transparent;
|
|
111
|
+
color: var(--hl-ink);
|
|
112
|
+
font-family: var(--hl-font-ui);
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
text-align: left;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.hl-outline-icon {
|
|
119
|
+
flex: none;
|
|
120
|
+
width: 20px;
|
|
121
|
+
height: 20px;
|
|
122
|
+
display: grid;
|
|
123
|
+
place-items: center;
|
|
124
|
+
border-radius: 6px;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
color: var(--hl-void);
|
|
127
|
+
background: var(--hl-silver-lo);
|
|
128
|
+
}
|
|
129
|
+
.hl-outline-icon.hl-kind-r { background: var(--hl-r); }
|
|
130
|
+
.hl-outline-icon.hl-kind-t { background: var(--hl-t); }
|
|
131
|
+
.hl-outline-icon.hl-kind-w { background: var(--hl-w); }
|
|
132
|
+
.hl-outline-thumb {
|
|
133
|
+
width: 100%;
|
|
134
|
+
height: 100%;
|
|
135
|
+
object-fit: cover;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.hl-outline-name {
|
|
139
|
+
flex: 1;
|
|
140
|
+
min-width: 0;
|
|
141
|
+
overflow: hidden;
|
|
142
|
+
text-overflow: ellipsis;
|
|
143
|
+
white-space: nowrap;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Edit-time diagnostic marker in a row. */
|
|
147
|
+
.hl-outline-diag {
|
|
148
|
+
flex: none;
|
|
149
|
+
display: grid;
|
|
150
|
+
place-items: center;
|
|
151
|
+
width: 16px;
|
|
152
|
+
height: 16px;
|
|
153
|
+
}
|
|
154
|
+
.hl-outline-diag.hl-diag-warning {
|
|
155
|
+
color: var(--hl-warning);
|
|
156
|
+
}
|
|
157
|
+
.hl-outline-diag.hl-diag-error {
|
|
158
|
+
color: var(--hl-error);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* Persistent state glyph inside the row (lock / slash-eye). Always visible when
|
|
162
|
+
its flag is on, so a hidden or locked layer is legible at rest — the state
|
|
163
|
+
doesn't hide behind hover. Silver so it reads as an intentional marker. */
|
|
164
|
+
.hl-outline-badge {
|
|
165
|
+
flex: none;
|
|
166
|
+
display: grid;
|
|
167
|
+
place-items: center;
|
|
168
|
+
color: var(--hl-silver);
|
|
169
|
+
opacity: 0.9;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Inline visible/lock controls — revealed on row hover or when selected. */
|
|
173
|
+
.hl-outline-controls {
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
gap: 2px;
|
|
177
|
+
padding-right: 6px;
|
|
178
|
+
opacity: 0;
|
|
179
|
+
transition: opacity 0.14s var(--hl-ease);
|
|
180
|
+
}
|
|
181
|
+
.hl-outline-row:hover .hl-outline-controls,
|
|
182
|
+
.hl-outline-row.is-active .hl-outline-controls,
|
|
183
|
+
/* Keep controls visible whenever a flag is active, so the toggled-on state is
|
|
184
|
+
always operable and never hidden behind hover. */
|
|
185
|
+
.hl-outline-row.is-hidden .hl-outline-controls,
|
|
186
|
+
.hl-outline-row.is-locked .hl-outline-controls {
|
|
187
|
+
opacity: 1;
|
|
188
|
+
}
|
|
189
|
+
.hl-outline-ctl {
|
|
190
|
+
width: 22px;
|
|
191
|
+
height: 22px;
|
|
192
|
+
display: grid;
|
|
193
|
+
place-items: center;
|
|
194
|
+
border: none;
|
|
195
|
+
background: transparent;
|
|
196
|
+
color: var(--hl-ink-3);
|
|
197
|
+
border-radius: 5px;
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
line-height: 1;
|
|
200
|
+
}
|
|
201
|
+
.hl-outline-ctl:hover {
|
|
202
|
+
background: rgba(255, 255, 255, 0.08);
|
|
203
|
+
color: var(--hl-ink);
|
|
204
|
+
}
|
|
205
|
+
/* An engaged control (hidden/locked ON) reads in silver. */
|
|
206
|
+
.hl-outline-ctl.is-active-ctl {
|
|
207
|
+
color: var(--hl-silver);
|
|
208
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
.hl-form {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 12px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.hl-field {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: 5px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.hl-field-label {
|
|
14
|
+
font-size: 11px;
|
|
15
|
+
font-weight: 500;
|
|
16
|
+
color: var(--hl-ink-2);
|
|
17
|
+
letter-spacing: 0.01em;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hl-input {
|
|
21
|
+
font-family: var(--hl-font-ui);
|
|
22
|
+
font-size: 12.5px;
|
|
23
|
+
color: var(--hl-ink);
|
|
24
|
+
background: var(--hl-void-2);
|
|
25
|
+
border: 1px solid var(--hl-line-strong);
|
|
26
|
+
border-radius: var(--hl-r-sm);
|
|
27
|
+
padding: 6px 9px;
|
|
28
|
+
width: 100%;
|
|
29
|
+
transition: border-color 0.15s var(--hl-ease);
|
|
30
|
+
resize: vertical;
|
|
31
|
+
}
|
|
32
|
+
.hl-input.hl-mono {
|
|
33
|
+
font-family: var(--hl-font-mono);
|
|
34
|
+
font-variant-numeric: tabular-nums;
|
|
35
|
+
}
|
|
36
|
+
.hl-input:hover {
|
|
37
|
+
border-color: color-mix(in oklab, var(--hl-silver) 30%, var(--hl-line-strong));
|
|
38
|
+
}
|
|
39
|
+
.hl-input:focus {
|
|
40
|
+
outline: none;
|
|
41
|
+
border-color: var(--hl-silver);
|
|
42
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--hl-silver) 18%, transparent);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Toggle pill */
|
|
46
|
+
.hl-toggle {
|
|
47
|
+
width: 34px;
|
|
48
|
+
height: 20px;
|
|
49
|
+
border-radius: 999px;
|
|
50
|
+
border: 1px solid var(--hl-line-strong);
|
|
51
|
+
background: var(--hl-void-2);
|
|
52
|
+
padding: 0;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
position: relative;
|
|
55
|
+
align-self: flex-start;
|
|
56
|
+
transition: background 0.18s var(--hl-ease), border-color 0.18s var(--hl-ease);
|
|
57
|
+
}
|
|
58
|
+
.hl-toggle-knob {
|
|
59
|
+
position: absolute;
|
|
60
|
+
top: 2px;
|
|
61
|
+
left: 2px;
|
|
62
|
+
width: 14px;
|
|
63
|
+
height: 14px;
|
|
64
|
+
border-radius: 50%;
|
|
65
|
+
background: var(--hl-ink-3);
|
|
66
|
+
transition: transform 0.18s var(--hl-ease), background 0.18s var(--hl-ease);
|
|
67
|
+
}
|
|
68
|
+
.hl-toggle.is-on {
|
|
69
|
+
background: color-mix(in oklab, var(--hl-silver) 28%, var(--hl-void-2));
|
|
70
|
+
border-color: var(--hl-silver);
|
|
71
|
+
}
|
|
72
|
+
.hl-toggle.is-on .hl-toggle-knob {
|
|
73
|
+
transform: translateX(14px);
|
|
74
|
+
background: var(--hl-silver);
|
|
75
|
+
}
|
|
76
|
+
.hl-toggle:focus-visible {
|
|
77
|
+
outline: 2px solid var(--hl-silver);
|
|
78
|
+
outline-offset: 2px;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.hl-field-custom {
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
color: var(--hl-ink-3);
|
|
84
|
+
padding: 6px 9px;
|
|
85
|
+
background: var(--hl-void-2);
|
|
86
|
+
border: 1px dashed var(--hl-line-strong);
|
|
87
|
+
border-radius: var(--hl-r-sm);
|
|
88
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** PositionPanel — align cluster + X/Y coordinates, in the inspector. */
|
|
2
|
+
|
|
3
|
+
.hl-position {
|
|
4
|
+
padding: 14px 16px 4px;
|
|
5
|
+
border-bottom: 1px solid var(--hl-line);
|
|
6
|
+
}
|
|
7
|
+
.hl-position-title {
|
|
8
|
+
font-size: 10px;
|
|
9
|
+
text-transform: uppercase;
|
|
10
|
+
letter-spacing: 0.16em;
|
|
11
|
+
color: var(--hl-silver-lo);
|
|
12
|
+
margin: 0 0 10px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.hl-position-align {
|
|
16
|
+
display: grid;
|
|
17
|
+
grid-template-columns: repeat(6, 1fr);
|
|
18
|
+
gap: 3px;
|
|
19
|
+
margin-bottom: 12px;
|
|
20
|
+
}
|
|
21
|
+
.hl-position-alignbtn {
|
|
22
|
+
height: 28px;
|
|
23
|
+
display: grid;
|
|
24
|
+
place-items: center;
|
|
25
|
+
border: 1px solid var(--hl-line);
|
|
26
|
+
background: rgba(255, 255, 255, 0.02);
|
|
27
|
+
color: var(--hl-ink-2);
|
|
28
|
+
border-radius: 6px;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
transition: background 0.14s var(--hl-ease), color 0.14s var(--hl-ease), border-color 0.14s var(--hl-ease);
|
|
31
|
+
}
|
|
32
|
+
.hl-position-alignbtn:hover:not(:disabled) {
|
|
33
|
+
background: rgba(255, 255, 255, 0.06);
|
|
34
|
+
color: var(--hl-ink);
|
|
35
|
+
border-color: color-mix(in oklab, var(--hl-silver) 40%, var(--hl-line-strong));
|
|
36
|
+
}
|
|
37
|
+
.hl-position-alignbtn:disabled {
|
|
38
|
+
opacity: 0.3;
|
|
39
|
+
cursor: not-allowed;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.hl-position-coords {
|
|
43
|
+
display: grid;
|
|
44
|
+
grid-template-columns: 1fr 1fr;
|
|
45
|
+
gap: 8px;
|
|
46
|
+
}
|
|
47
|
+
.hl-position-field {
|
|
48
|
+
/* min-width:0 is load-bearing: without it the number input's intrinsic
|
|
49
|
+
min-width overflows the 1fr grid track and the second field spills past the
|
|
50
|
+
rail's right edge. */
|
|
51
|
+
min-width: 0;
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 6px;
|
|
55
|
+
background: rgba(255, 255, 255, 0.03);
|
|
56
|
+
border: 1px solid var(--hl-line-strong);
|
|
57
|
+
border-radius: var(--hl-r-sm);
|
|
58
|
+
padding: 0 9px;
|
|
59
|
+
}
|
|
60
|
+
.hl-position-field:focus-within {
|
|
61
|
+
border-color: color-mix(in oklab, var(--hl-silver) 45%, var(--hl-line-strong));
|
|
62
|
+
}
|
|
63
|
+
.hl-position-input {
|
|
64
|
+
flex: 1;
|
|
65
|
+
min-width: 0;
|
|
66
|
+
height: 30px;
|
|
67
|
+
border: none;
|
|
68
|
+
background: transparent;
|
|
69
|
+
color: var(--hl-ink);
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
outline: none;
|
|
72
|
+
/* strip number spinners */
|
|
73
|
+
appearance: textfield;
|
|
74
|
+
-moz-appearance: textfield;
|
|
75
|
+
}
|
|
76
|
+
.hl-position-input::-webkit-outer-spin-button,
|
|
77
|
+
.hl-position-input::-webkit-inner-spin-button {
|
|
78
|
+
-webkit-appearance: none;
|
|
79
|
+
margin: 0;
|
|
80
|
+
}
|
|
81
|
+
.hl-position-input:disabled {
|
|
82
|
+
color: var(--hl-ink-3);
|
|
83
|
+
}
|
|
84
|
+
.hl-position-axis {
|
|
85
|
+
font-size: 11px;
|
|
86
|
+
color: var(--hl-ink-3);
|
|
87
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** PreviewPanel — a glass-framed result image, the graph's "output". */
|
|
2
|
+
|
|
3
|
+
.hl-preview {
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
gap: 8px;
|
|
7
|
+
padding: 14px 14px 0;
|
|
8
|
+
/* In a vertical flex host (right rail) the preview must not be squeezed by a
|
|
9
|
+
taller sibling (inspector) — otherwise the square frame collapses to a
|
|
10
|
+
sliver. It keeps its intrinsic height. */
|
|
11
|
+
flex: none;
|
|
12
|
+
}
|
|
13
|
+
.hl-preview-head {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: baseline;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
}
|
|
18
|
+
.hl-preview-title {
|
|
19
|
+
font-size: 11px;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
text-transform: uppercase;
|
|
22
|
+
letter-spacing: 0.14em;
|
|
23
|
+
color: var(--hl-ink-3);
|
|
24
|
+
}
|
|
25
|
+
.hl-preview-status {
|
|
26
|
+
font-size: 10px;
|
|
27
|
+
color: var(--hl-silver);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hl-preview-frame {
|
|
31
|
+
border-radius: var(--hl-r-md);
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
aspect-ratio: 1 / 1;
|
|
34
|
+
background: var(--hl-void-2);
|
|
35
|
+
box-shadow: var(--hl-glass-edge), var(--hl-shadow-node);
|
|
36
|
+
}
|
|
37
|
+
.hl-preview-img {
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 100%;
|
|
40
|
+
object-fit: cover;
|
|
41
|
+
display: block;
|
|
42
|
+
}
|
|
43
|
+
.hl-preview-placeholder {
|
|
44
|
+
width: 100%;
|
|
45
|
+
height: 100%;
|
|
46
|
+
display: grid;
|
|
47
|
+
place-items: center;
|
|
48
|
+
font-size: 11px;
|
|
49
|
+
color: var(--hl-ink-3);
|
|
50
|
+
background: linear-gradient(135deg, var(--hl-surface-2), var(--hl-void-2));
|
|
51
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** RailTabs — segmented glass tab strip for a side rail. */
|
|
2
|
+
|
|
3
|
+
.hl-railtabs {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 2px;
|
|
7
|
+
margin: 12px 12px 6px;
|
|
8
|
+
padding: 3px;
|
|
9
|
+
background: rgba(255, 255, 255, 0.03);
|
|
10
|
+
border: 1px solid var(--hl-line);
|
|
11
|
+
border-radius: var(--hl-r-sm);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.hl-railtab {
|
|
15
|
+
flex: 1;
|
|
16
|
+
padding: 6px 8px;
|
|
17
|
+
border: none;
|
|
18
|
+
background: transparent;
|
|
19
|
+
color: var(--hl-ink-3);
|
|
20
|
+
font-family: var(--hl-font-ui);
|
|
21
|
+
font-size: 12px;
|
|
22
|
+
font-weight: 550;
|
|
23
|
+
border-radius: 6px;
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
transition: background 0.14s var(--hl-ease), color 0.14s var(--hl-ease);
|
|
26
|
+
}
|
|
27
|
+
.hl-railtab:hover {
|
|
28
|
+
color: var(--hl-ink-2);
|
|
29
|
+
}
|
|
30
|
+
.hl-railtab.is-active {
|
|
31
|
+
color: var(--hl-ink);
|
|
32
|
+
background: color-mix(in oklab, var(--hl-silver) 16%, transparent);
|
|
33
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--hl-silver) 24%, transparent);
|
|
34
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditorShell layout. A column of [toolbar / body / footer]; the body is a row
|
|
3
|
+
* of [left | canvas | right]. Panels are fixed-width, the canvas flexes.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.hl-shell {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
/* A faint silver ambient wash from the top — expensive, calm, no color cast. */
|
|
12
|
+
background:
|
|
13
|
+
radial-gradient(120% 80% at 50% -10%, rgba(200, 204, 212, 0.05), transparent 60%),
|
|
14
|
+
var(--hl-void);
|
|
15
|
+
color: var(--hl-ink);
|
|
16
|
+
font-family: var(--hl-font-ui);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.hl-region-toolbar {
|
|
20
|
+
flex-shrink: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.hl-region-body {
|
|
24
|
+
flex: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
min-height: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Side panels are frosted glass, so the canvas beneath washes through their
|
|
30
|
+
edges — this is what makes the material read as glass, not flat panels. */
|
|
31
|
+
.hl-region-left {
|
|
32
|
+
width: 248px;
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
border-right: 1px solid var(--hl-line);
|
|
35
|
+
background: var(--hl-glass);
|
|
36
|
+
backdrop-filter: blur(var(--hl-glass-blur)) saturate(var(--hl-glass-sat));
|
|
37
|
+
-webkit-backdrop-filter: blur(var(--hl-glass-blur)) saturate(var(--hl-glass-sat));
|
|
38
|
+
box-shadow: var(--hl-glass-edge);
|
|
39
|
+
overflow: hidden; /* children own their scroll regions */
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.hl-region-canvas {
|
|
43
|
+
flex: 1;
|
|
44
|
+
position: relative;
|
|
45
|
+
min-width: 0;
|
|
46
|
+
}
|
|
47
|
+
/* A soft ambient pool of light in the canvas centre gives the glass panels and
|
|
48
|
+
nodes something luminous to sit over — depth, the opposite of a flat void. */
|
|
49
|
+
.hl-region-canvas::before {
|
|
50
|
+
content: '';
|
|
51
|
+
position: absolute;
|
|
52
|
+
inset: 0;
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
background: radial-gradient(
|
|
55
|
+
60% 55% at 50% 42%,
|
|
56
|
+
rgba(200, 204, 212, 0.05),
|
|
57
|
+
transparent 70%
|
|
58
|
+
);
|
|
59
|
+
z-index: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.hl-region-right {
|
|
63
|
+
width: 312px;
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
border-left: 1px solid var(--hl-line);
|
|
66
|
+
background: var(--hl-glass);
|
|
67
|
+
backdrop-filter: blur(var(--hl-glass-blur)) saturate(var(--hl-glass-sat));
|
|
68
|
+
-webkit-backdrop-filter: blur(var(--hl-glass-blur)) saturate(var(--hl-glass-sat));
|
|
69
|
+
box-shadow: var(--hl-glass-edge);
|
|
70
|
+
overflow: hidden; /* children own their scroll regions */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.hl-region-footer {
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
}
|