fix(editor): solid-filled connected port + larger dot + tooltip fallback
Three issues from Stefan's screenshot:
1. Connected port dots rendered as a ring with a small
surface-coloured pin in the centre — read as a hollow
bullseye target rather than 'this port is wired'.
Stefan asked for a plain filled circle: removed the
inner pin so connected = solid disc, disconnected =
ring with surface fill. One unambiguous visual switch.
2. Port dots bumped from 12 px to 14 px diameter. At 50 %
zoom (and under the wider cards we now draw) the 12 px
outline was sinking into the canvas background.
3. Tooltips now appear on every visible port label, not
only on those whose ModuleSpec carries a description.
Fallback chain:
- manifest description in active locale
- manifest description in English (peer)
- 'fieldname · type' when the field is declared but
the description is missing
- bare 'fieldname' for implicit (YAML-only) fields
Operators always see something on hover, useful when
the hub binary is older than the per-field ModuleInfo
RPC and the editor is running in implicit-only mode.
Bumps fai_studio_flow_editor to 0.10.3.
Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
3a6e92fe09
commit
a1d25fd48a
3 changed files with 57 additions and 54 deletions
|
|
@ -746,16 +746,34 @@ class _FlowCanvasState extends State<FlowCanvas>
|
|||
final spec = _specForStep(step);
|
||||
final inputLabels = _inputLabelsForStep(step);
|
||||
final outputLabels = _outputLabelsForStep(step);
|
||||
// Tooltips: every visible label gets one. When the
|
||||
// manifest carries a locale description, use it. Else
|
||||
// fall back to `name (type)` for declared fields whose
|
||||
// description is missing, or to the bare field name for
|
||||
// implicit (YAML-only) fields. Operators always see
|
||||
// something on hover — useful at least to confirm the
|
||||
// exact field they're pointing at.
|
||||
final tooltips = <String, String>{};
|
||||
final loc = widget.locale == FlowEditorLocale.de ? 'de' : 'en';
|
||||
final declaredFields = <String, ModuleField>{};
|
||||
if (spec != null) {
|
||||
final loc = widget.locale == FlowEditorLocale.de ? 'de' : 'en';
|
||||
for (final f in spec.inputs) {
|
||||
final d = f.descriptionFor(loc);
|
||||
if (d != null) tooltips[f.name] = d;
|
||||
for (final f in [...spec.inputs, ...spec.outputs]) {
|
||||
declaredFields[f.name] = f;
|
||||
}
|
||||
for (final f in spec.outputs) {
|
||||
}
|
||||
for (final label in [...inputLabels, ...outputLabels]) {
|
||||
final f = declaredFields[label];
|
||||
if (f != null) {
|
||||
final d = f.descriptionFor(loc);
|
||||
if (d != null) tooltips[f.name] = d;
|
||||
if (d != null && d.isNotEmpty) {
|
||||
tooltips[label] = d;
|
||||
} else if (f.type.isNotEmpty) {
|
||||
tooltips[label] = '$label · ${f.type}';
|
||||
} else {
|
||||
tooltips[label] = label;
|
||||
}
|
||||
} else {
|
||||
tooltips[label] = label;
|
||||
}
|
||||
}
|
||||
final cardHeight = NodeGeometry.heightFor(
|
||||
|
|
@ -1714,50 +1732,32 @@ class _FlowCanvasState extends State<FlowCanvas>
|
|||
onLongPressStart: onContextMenu == null
|
||||
? null
|
||||
: (details) => onContextMenu(details.globalPosition),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// Outer ring — defines the port's footprint.
|
||||
// Filled when connected (so the line "docks"
|
||||
// into a visible target), surface-filled when
|
||||
// dangling (a clear empty socket). Drop-target
|
||||
// halo grows + glows.
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: filled ? accent : theme.colorScheme.surface,
|
||||
border: Border.all(
|
||||
color: accent,
|
||||
width: isClosest ? 2.5 : (isHovered ? 2.2 : 1.8),
|
||||
),
|
||||
boxShadow: (isClosest || isHovered)
|
||||
? [
|
||||
BoxShadow(
|
||||
color: accent.withValues(
|
||||
alpha: isClosest ? 0.55 : 0.35,
|
||||
),
|
||||
blurRadius: isClosest ? 10 : 6,
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
child: Container(
|
||||
// Connected = solid filled circle in accent.
|
||||
// Dangling = clear ring with surface fill so the
|
||||
// empty socket is obvious. Drop-target halo
|
||||
// glows in addition. No inner pin — Stefan
|
||||
// explicitly wants the connected variant to read
|
||||
// as one continuous filled disc, not a ring with
|
||||
// a bullseye in it.
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: filled ? accent : theme.colorScheme.surface,
|
||||
border: Border.all(
|
||||
color: accent,
|
||||
width: isClosest ? 2.5 : (isHovered ? 2.2 : 1.8),
|
||||
),
|
||||
// Inner pin — tiny surface-coloured dot at the
|
||||
// centre when connected, giving the port the
|
||||
// "socket with a pin in it" look that reads as
|
||||
// an active electrical connector rather than a
|
||||
// free-floating indicator. Skipped on empty
|
||||
// ports so the hollow ring is unambiguous.
|
||||
if (connected)
|
||||
Container(
|
||||
width: 4,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surface,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
],
|
||||
boxShadow: (isClosest || isHovered)
|
||||
? [
|
||||
BoxShadow(
|
||||
color: accent.withValues(
|
||||
alpha: isClosest ? 0.55 : 0.35,
|
||||
),
|
||||
blurRadius: isClosest ? 10 : 6,
|
||||
),
|
||||
]
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -83,10 +83,13 @@ class NodeGeometry {
|
|||
/// without overlapping the label text.
|
||||
static const double portGutter = 18;
|
||||
|
||||
/// Diameter of the canvas-side port dot — sized to the
|
||||
/// body's labelSmall row (~11 px text + 11 px breathing
|
||||
/// room) so the dot reads as the port without crowding.
|
||||
static const double portDotSize = 12;
|
||||
/// Diameter of the canvas-side port dot. Sized so the
|
||||
/// connected-vs-outlined state reads clearly at any zoom:
|
||||
/// a 12 px outline tends to disappear into the background
|
||||
/// at 50 % zoom; 14 px keeps the ring visible and gives
|
||||
/// the filled (connected) variant enough mass to stand out
|
||||
/// against the card shadow.
|
||||
static const double portDotSize = 14;
|
||||
|
||||
/// Total card height for a node carrying [inputCount] inputs
|
||||
/// on the left + [outputCount] outputs on the right. The
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name: fai_studio_flow_editor
|
||||
description: Swappable inline YAML editor for F∆I Studio flows.
|
||||
version: 0.10.2
|
||||
version: 0.10.3
|
||||
publish_to: 'none'
|
||||
repository: https://git.flemming.ai/fai/studio-flow-editor
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue