mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(ui/workflows): canvas controls dark-theme + reliable node-click
This commit is contained in:
parent
12bd05382e
commit
789af09772
@ -276,39 +276,66 @@ html.dark {
|
||||
|
||||
/* Vue Flow theme bridge — its default stylesheet ships hard-coded
|
||||
light colors for handles / mini-map / control buttons. Map them to
|
||||
our theme tokens so dark mode inherits cleanly. */
|
||||
.vue-flow__handle {
|
||||
our theme tokens so dark mode inherits cleanly.
|
||||
|
||||
Each selector is bumped to (0,2,0) specificity by scoping to
|
||||
`.workflow-canvas` because vue-flow's component CSS imports inside
|
||||
WorkflowCanvas.vue land in the bundle AFTER main.css; equal
|
||||
specificity would lose. */
|
||||
.workflow-canvas .vue-flow__handle {
|
||||
background: var(--mc-edge-strong, #777);
|
||||
border-color: var(--mc-bg-elevated, #fff);
|
||||
}
|
||||
.vue-flow__edge-path {
|
||||
.workflow-canvas .vue-flow__edge-path {
|
||||
stroke: var(--mc-edge, #999);
|
||||
}
|
||||
.vue-flow__edge-text {
|
||||
.workflow-canvas .vue-flow__edge-text {
|
||||
fill: var(--mc-text-secondary, #555);
|
||||
font-size: 11px;
|
||||
}
|
||||
.vue-flow__edge-textbg {
|
||||
.workflow-canvas .vue-flow__edge-textbg {
|
||||
fill: var(--mc-bg-elevated, #fff);
|
||||
}
|
||||
.vue-flow__minimap {
|
||||
background: var(--mc-bg-sunken, rgba(0, 0, 0, 0.04)) !important;
|
||||
.workflow-canvas .vue-flow__background {
|
||||
background: transparent;
|
||||
}
|
||||
.workflow-canvas .vue-flow__minimap {
|
||||
background: var(--mc-bg-sunken, rgba(0, 0, 0, 0.04));
|
||||
border: 1px solid var(--mc-border-light, rgba(0, 0, 0, 0.08));
|
||||
border-radius: 6px;
|
||||
}
|
||||
.workflow-canvas .vue-flow__minimap-mask {
|
||||
fill: var(--mc-bg-muted, rgba(0, 0, 0, 0.06));
|
||||
stroke: var(--mc-border, transparent);
|
||||
}
|
||||
.workflow-canvas .vue-flow__controls {
|
||||
box-shadow: var(--mc-shadow-soft, 0 2px 6px rgba(0, 0, 0, 0.1));
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: var(--mc-bg-elevated, #ffffff);
|
||||
border: 1px solid var(--mc-border-light, rgba(0, 0, 0, 0.08));
|
||||
}
|
||||
.vue-flow__minimap-mask {
|
||||
fill: var(--mc-bg-muted, rgba(0, 0, 0, 0.06));
|
||||
}
|
||||
.vue-flow__controls {
|
||||
box-shadow: var(--mc-shadow-soft, 0 2px 6px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
.vue-flow__controls-button {
|
||||
background: var(--mc-bg-elevated, #fff);
|
||||
border-bottom-color: var(--mc-border-light, rgba(0, 0, 0, 0.08));
|
||||
.workflow-canvas .vue-flow__controls-button {
|
||||
background: var(--mc-bg-elevated, #ffffff);
|
||||
border-bottom: 1px solid var(--mc-border-light, rgba(0, 0, 0, 0.08));
|
||||
fill: var(--mc-text-primary, #333);
|
||||
color: var(--mc-text-primary, #333);
|
||||
}
|
||||
.vue-flow__controls-button:hover {
|
||||
.workflow-canvas .vue-flow__controls-button svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
.workflow-canvas .vue-flow__controls-button:hover {
|
||||
background: var(--mc-bg-muted, rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
/* Round the bottom button so the corner doesn't show the hardcoded grey
|
||||
border vue-flow ships with. */
|
||||
.workflow-canvas .vue-flow__controls-button:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
/* Selection ring matches the brand accent in both modes. */
|
||||
.workflow-canvas .vue-flow__node.selected {
|
||||
box-shadow: 0 0 0 2px var(--mc-primary, #4084ff);
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
Base resets
|
||||
|
||||
@ -3,8 +3,7 @@
|
||||
class="step-node"
|
||||
:class="`mode-${data.modeType}`"
|
||||
:data-selected="props.selected"
|
||||
@click.stop="handleClick"
|
||||
@pointerdown.stop
|
||||
@click="handleClick"
|
||||
>
|
||||
<Handle type="target" :position="targetPosition" />
|
||||
<div class="step-band" />
|
||||
|
||||
@ -79,9 +79,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, markRaw, onBeforeUnmount, provide, ref, watch } from 'vue'
|
||||
import { computed, markRaw, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { VueFlow, type Node } from '@vue-flow/core'
|
||||
import { VueFlow, useVueFlow, type Node } from '@vue-flow/core'
|
||||
import { Background } from '@vue-flow/background'
|
||||
import { Controls } from '@vue-flow/controls'
|
||||
import { MiniMap } from '@vue-flow/minimap'
|
||||
@ -139,19 +139,31 @@ const miniNodeColor = (node: Node<StepNodeData>) => {
|
||||
}
|
||||
const miniNodeStrokeColor = () => 'transparent'
|
||||
|
||||
// Vue-flow's `@node-click` event signature has shifted across minor
|
||||
// versions and sometimes doesn't fire reliably for custom-node templates
|
||||
// because the click can be swallowed by the inner DOM. Bypass it: we
|
||||
// provide a selection callback to the StepNode via inject, and the node
|
||||
// invokes it directly on its own click handler.
|
||||
// Three independent paths for getting a node click out of vue-flow into
|
||||
// the parent's inspector — at least one always works regardless of how
|
||||
// the click lands inside vue-flow's internal DOM.
|
||||
//
|
||||
// 1. `useVueFlow().onNodeClick` — the official subscription API tied
|
||||
// to the flow instance keyed by props.canvasId.
|
||||
// 2. `provide('selectStepCallback', ...)` — the StepNode injects this
|
||||
// and fires it on its own @click. Survives vue-flow re-renders.
|
||||
// 3. The template `@node-click` attribute below — kept as a third
|
||||
// fallback for completeness.
|
||||
function selectStep(data: StepNodeData | null) {
|
||||
emit('select-step', data)
|
||||
}
|
||||
provide('selectStepCallback', selectStep)
|
||||
|
||||
const flow = useVueFlow(props.canvasId)
|
||||
onMounted(() => {
|
||||
flow.onNodeClick((evt) => {
|
||||
const data = (evt?.node as Node<StepNodeData> | undefined)?.data
|
||||
if (data) selectStep(data)
|
||||
})
|
||||
flow.onPaneClick(() => selectStep(null))
|
||||
})
|
||||
|
||||
function handleNodeClick(payload: { node: Node<StepNodeData> } | unknown) {
|
||||
// Backup path: if vue-flow does fire its own node-click event with the
|
||||
// expected shape, route it through the same emit.
|
||||
const node = (payload as { node?: Node<StepNodeData> })?.node
|
||||
if (node?.data) selectStep(node.data)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user