perf: 完善黑夜模式的表现效果,工作流编排幕布和节点在黑夜模式正常表现

This commit is contained in:
2026-03-04 19:56:20 +08:00
parent 27376a5f33
commit a79718b03b
33 changed files with 605 additions and 363 deletions

View File

@@ -1,6 +1,6 @@
import {type useSvelteFlow} from '@xyflow/svelte';
import type {useSvelteFlow} from '@xyflow/svelte';
import {componentName} from './consts';
import type {TinyflowData, TinyflowOptions} from './types';
import type {TinyflowData, TinyflowOptions, TinyflowTheme} from './types';
type FlowInstance = ReturnType<typeof useSvelteFlow>;
@@ -8,6 +8,10 @@ export class Tinyflow {
private options!: TinyflowOptions;
private rootEl!: Element;
private svelteFlowInstance!: FlowInstance;
private tinyflowEl!: HTMLElement & {
options: TinyflowOptions;
onInit: (svelteFlowInstance: FlowInstance) => void;
};
constructor(options: TinyflowOptions) {
if (typeof options.element !== 'string' && !(options.element instanceof Element)) {
@@ -38,20 +42,13 @@ export class Tinyflow {
tinyflowEl.style.display = 'block';
tinyflowEl.style.width = '100%';
tinyflowEl.style.height = '100%';
tinyflowEl.classList.add('tf-theme-light');
this._applyThemeClass(tinyflowEl, this.options.theme);
tinyflowEl.options = this.options;
tinyflowEl.onInit = (svelteFlowInstance: FlowInstance) => {
this.svelteFlowInstance = svelteFlowInstance;
};
this.rootEl.appendChild(tinyflowEl);
}
private _setOptions(options: TinyflowOptions) {
this.options = {
...options
};
return tinyflowEl;
}
getOptions() {
@@ -62,25 +59,20 @@ export class Tinyflow {
return this.svelteFlowInstance.toObject();
}
setTheme(theme: TinyflowTheme) {
this.options.theme = theme;
if (this.tinyflowEl) {
this._applyThemeClass(this.tinyflowEl, theme);
}
}
setData(data: TinyflowData) {
this.options.data = data;
const tinyflowEl = document.createElement(componentName) as HTMLElement & {
options: TinyflowOptions;
onInit: (svelteFlowInstance: FlowInstance) => void;
};
tinyflowEl.style.display = 'block';
tinyflowEl.style.width = '100%';
tinyflowEl.style.height = '100%';
tinyflowEl.classList.add('tf-theme-light');
tinyflowEl.options = this.options;
tinyflowEl.onInit = (svelteFlowInstance: FlowInstance) => {
this.svelteFlowInstance = svelteFlowInstance;
};
this.tinyflowEl = this._createTinyflowElement();
this.destroy();
this.rootEl.appendChild(tinyflowEl);
this.rootEl.appendChild(this.tinyflowEl);
}
destroy() {

View File

@@ -461,17 +461,18 @@
<style>
.panel-content {
padding: 10px;
background-color: #fff;
background-color: var(--tf-bg-surface);
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-soft);
width: 200px;
border: 1px solid #efefef;
border: 1px solid var(--tf-border-color);
color: var(--tf-text-primary);
}
.setting-title {
margin: 10px 0;
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
}
.setting-item {
@@ -487,13 +488,13 @@
.readonly-edge-branch {
font-size: 12px;
color: #6b7280;
color: var(--tf-text-secondary);
margin-bottom: 8px;
}
.readonly-edge-tip {
margin-top: 6px;
font-size: 12px;
color: #9ca3af;
color: var(--tf-text-muted);
}
</style>

View File

@@ -91,8 +91,8 @@
width: 16px;
height: 16px;
border-radius: 50%;
border: 1px solid #c6cfdd;
color: #64748b;
border: 1px solid var(--tf-border-color-strong);
color: var(--tf-text-secondary);
display: inline-flex;
align-items: center;
justify-content: center;
@@ -100,14 +100,14 @@
line-height: 1;
cursor: default;
user-select: none;
background: #fff;
background: var(--tf-bg-surface);
position: relative;
}
.tf-collapse-item-title-help:hover {
border-color: #94a3b8;
color: #334155;
background: #f8fafc;
border-color: var(--tf-border-color-strong);
color: var(--tf-text-primary);
background: var(--tf-bg-hover);
}
.tf-collapse-item-title-help::after {
@@ -119,13 +119,13 @@
min-width: 260px;
max-width: 420px;
white-space: pre-line;
background: #0f172a;
color: #f8fafc;
background: var(--tf-tip-bg);
color: var(--tf-tip-text);
border-radius: 8px;
padding: 10px 12px;
font-size: 12px;
line-height: 1.45;
box-shadow: 0 8px 22px rgba(2, 6, 23, 0.25);
box-shadow: var(--tf-shadow-medium);
opacity: 0;
visibility: hidden;
pointer-events: none;
@@ -140,7 +140,7 @@
transform: translateY(-50%);
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 6px solid #0f172a;
border-right: 6px solid var(--tf-tip-bg);
opacity: 0;
visibility: hidden;
z-index: 121;

View File

@@ -18,7 +18,7 @@
padding: 3px;
&:hover {
background: #eee;
background: var(--tf-bg-hover);
border: 1px solid transparent;
}
}

View File

@@ -227,8 +227,8 @@
}
.tf-mixed-ref-box {
background-color: #ffffff;
border: 1px solid #d1d5db;
background-color: var(--tf-bg-input);
border: 1px solid var(--tf-border-color-strong);
padding: 0 48px 0 12px;
align-items: center;
cursor: pointer;
@@ -236,8 +236,8 @@
}
.tf-mixed-text-box {
background-color: #ffffff;
border: 1px solid #d1d5db;
background-color: var(--tf-bg-input);
border: 1px solid var(--tf-border-color-strong);
padding: 0 48px 0 12px;
align-items: center;
transition: all 0.2s;
@@ -247,13 +247,13 @@
.tf-mixed-wrapper.is-focus .tf-mixed-text-box,
.tf-mixed-ref-box:hover,
.tf-mixed-text-box:hover {
border-color: #94a3b8;
border-color: var(--tf-border-color-strong);
}
.tf-mixed-wrapper.is-focus .tf-mixed-ref-box,
.tf-mixed-wrapper.is-focus .tf-mixed-text-box {
border-color: #3b82f6;
border-color: var(--tf-primary-color);
outline: none;
box-shadow: 0 0 0 2px rgba(59,130,246,0.1);
box-shadow: var(--tf-focus-shadow);
}
.tf-mixed-sel-val {
@@ -272,8 +272,8 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #3474ff;
background: #cedafb;
color: var(--tf-icon-color);
background: var(--tf-icon-bg);
border-radius: 4px;
padding: 2px;
box-sizing: border-box;
@@ -281,9 +281,9 @@
:global(svg) { width: 12px; height: 12px; }
}
.tf-mixed-val-name { color: #111827; font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; user-select: none; }
.tf-mixed-val-name { color: var(--tf-text-primary); font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; user-select: none; }
.tf-mixed-placeholder {
color: #9ca3af;
color: var(--tf-text-muted);
font-size: 13px;
height: 100%;
display: flex;
@@ -301,12 +301,12 @@
align-items: center;
justify-content: center;
cursor: pointer;
color: #94a3b8;
color: var(--tf-text-muted);
border-radius: 0 5px 5px 0;
transition: all 0.2s;
flex-shrink: 0;
&:hover { background: rgba(0,0,0,0.04); color: #64748b; }
&:hover { background: var(--tf-bg-tag); color: var(--tf-text-secondary); }
}
/* Keep the trigger in the same visual position in both text/ref modes */
@@ -330,10 +330,10 @@
height: 20px;
top: 50%;
transform: translateY(-50%);
background: #e2e8f0;
background: var(--tf-bg-active);
border: none;
border-radius: 50%;
color: #64748b;
color: var(--tf-text-secondary);
display: flex;
align-items: center;
justify-content: center;
@@ -343,7 +343,7 @@
padding: 3px;
z-index: 10;
}
.tf-mixed-clear-btn:hover { background: #ef4444; color: #fff; }
.tf-mixed-clear-btn:hover { background: var(--tf-danger-color); color: var(--tf-bg-surface); }
.tf-mixed-wrapper:hover .tf-mixed-clear-btn { opacity: 1; }
.tf-mixed-native-input {
@@ -352,7 +352,7 @@
border: none;
outline: none;
background: transparent;
color: #111827;
color: var(--tf-text-primary);
font-size: 13px;
line-height: 32px;
height: 32px;
@@ -363,17 +363,17 @@
}
.tf-mixed-native-input::placeholder {
color: #9ca3af;
color: var(--tf-text-muted);
line-height: 32px;
}
/* Dropdown Styles matched perfectly to Select */
.tf-mixed-dropdown {
display: flex;
background: #fff;
background: var(--tf-bg-surface);
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0,0,0,0.15);
border: 1px solid #e5e7eb;
box-shadow: var(--tf-shadow-medium);
border: 1px solid var(--tf-border-color);
overflow: hidden;
width: max-content;
box-sizing: border-box;
@@ -382,9 +382,9 @@
margin-top: 5px;
}
.tf-mixed-list { display: flex; flex-direction: column; padding: 8px; overflow-y: auto; }
.tf-mixed-primary-list { width: 100%; flex-shrink: 0; background: #f9fafb; }
.tf-mixed-primary-list { width: 100%; flex-shrink: 0; background: var(--tf-bg-surface-alt); }
.tf-mixed-dropdown:has(.tf-mixed-secondary-list) .tf-mixed-primary-list { width: auto; min-width: 180px; }
.tf-mixed-secondary-list { min-width: 220px; background: #fff; padding: 12px; border-left: 1px solid #f3f4f6; animation: slideIn 0.2s ease-out; box-sizing: border-box; }
.tf-mixed-secondary-list { min-width: 220px; background: var(--tf-bg-surface); padding: 12px; border-left: 1px solid var(--tf-bg-muted); animation: slideIn 0.2s ease-out; box-sizing: border-box; }
@keyframes slideIn { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: translateX(0); } }
@@ -398,28 +398,28 @@
cursor: pointer;
text-align: left;
font-size: 13px;
color: #374151;
color: var(--tf-text-primary);
gap: 10px;
width: 100%;
transition: all 0.15s;
margin-bottom: 2px;
&:hover { background: #f3f4f6; }
&.active { background: #eff6ff; color: #2563eb; font-weight: 500; }
&.has-children { background: #f8fafc; margin-bottom: 4px; &:hover { background: #f1f5f9; } }
&:hover { background: var(--tf-bg-muted); }
&.active { background: var(--tf-primary-soft-bg); color: var(--tf-primary-color); font-weight: 500; }
&.has-children { background: var(--tf-bg-hover); margin-bottom: 4px; &:hover { background: var(--tf-bg-active); } }
}
.tf-mixed-item-icon {
width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: #3474ff; background: #cedafb; border-radius: 5px; padding: 3px; box-sizing: border-box;
width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--tf-icon-color); background: var(--tf-icon-bg); border-radius: 5px; padding: 3px; box-sizing: border-box;
:global(svg) { width: 16px; height: 16px; }
}
.tf-mixed-item-label { flex-grow: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tf-mixed-item-arrow { width: 14px; height: 14px; color: #9ca3af; }
.tf-mixed-item-arrow { width: 14px; height: 14px; color: var(--tf-text-muted); }
.tf-mixed-item-container { position: relative; width: 100%; }
.tf-mixed-item-children { position: relative; width: 100%; &::before { content: ''; position: absolute; left: 8px; top: 0; bottom: 0; width: 1px; background: #f0f0f0; } }
.tf-mixed-item-children { position: relative; width: 100%; &::before { content: ''; position: absolute; left: 8px; top: 0; bottom: 0; width: 1px; background: var(--tf-border-color-soft); } }
.tf-mixed-label { display: flex; justify-content: flex-start; align-items: center; width: 100%; gap: 8px; overflow: hidden;}
.tf-mixed-name-wrapper { display: flex; align-items: center; gap: 6px; }
.tf-mixed-expand-icon { width: 12px; height: 12px; color: currentColor; opacity: 0.6; }
.tf-mixed-name { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tf-mixed-type { background: rgba(0,0,0,0.06); color: #6b7280; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 500; white-space: nowrap; }
.tf-mixed-type { background: var(--tf-bg-tag); color: var(--tf-text-secondary); padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 500; white-space: nowrap; }
</style>

View File

@@ -309,9 +309,9 @@
.tf-select-default-wrapper {
display: flex;
flex-direction: column;
background: #fff;
background: var(--tf-bg-surface);
margin-top: 5px;
border: 1px solid #e5e7eb;
border: 1px solid var(--tf-border-color);
border-radius: 6px;
padding: 4px;
width: 100%;
@@ -319,7 +319,7 @@
box-sizing: border-box;
max-height: 220px;
overflow: auto;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
box-shadow: var(--tf-shadow-soft);
}
.tf-select-default-item {
@@ -327,7 +327,7 @@
align-items: center;
padding: 6px 12px;
border: none;
background: #fff;
background: var(--tf-bg-surface);
border-radius: 4px;
cursor: pointer;
line-height: 1.5;
@@ -335,10 +335,10 @@
width: 100%;
text-align: left;
font-size: 13px;
color: #111827;
color: var(--tf-text-primary);
&:hover {
background: #f5f5f7;
background: var(--tf-bg-hover);
}
}
@@ -351,16 +351,16 @@
.tf-select-model-wrapper {
display: flex;
flex-direction: column;
background: #fff;
background: var(--tf-bg-surface);
margin-top: 5px;
border: 1px solid #e5e7eb;
border: 1px solid var(--tf-border-color);
border-radius: 10px;
/* Removed fixed width to allow syncWidth to control it */
z-index: 99999;
box-sizing: border-box;
max-height: 400px;
overflow: hidden;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
box-shadow: var(--tf-shadow-medium);
}
.tf-select-model-header {
@@ -368,20 +368,20 @@
justify-content: space-between;
align-items: center;
padding: 10px 12px;
border-bottom: 1px solid #f3f4f6;
background: #fff;
border-bottom: 1px solid var(--tf-bg-muted);
background: var(--tf-bg-surface);
}
.tf-select-model-header-title {
font-size: 13px;
font-weight: 600;
color: #111827;
color: var(--tf-text-primary);
}
.tf-select-model-header-icon {
width: 14px;
height: 14px;
color: #6b7280;
color: var(--tf-text-secondary);
cursor: pointer;
}
@@ -396,7 +396,7 @@
.tf-select-model-group-title {
font-size: 12px;
font-weight: 500;
color: #6b7280;
color: var(--tf-text-secondary);
margin-top: 6px;
margin-bottom: 2px;
padding-left: 6px;
@@ -438,11 +438,11 @@
}
.tf-select-model-item:hover {
background: #f9fafb;
background: var(--tf-bg-surface-alt);
}
.tf-select-model-item.active {
background: #e0e7ff;
background: var(--tf-primary-soft-bg);
}
.tf-select-model-icon {
@@ -454,7 +454,7 @@
display: flex;
align-items: center;
justify-content: center;
background: #f3f4f6;
background: var(--tf-bg-muted);
margin-top: 2px;
}
@@ -467,7 +467,7 @@
.tf-select-model-avatar {
font-size: 14px;
font-weight: 600;
color: #9ca3af;
color: var(--tf-text-muted);
}
.tf-select-model-info {
@@ -481,7 +481,7 @@
.tf-select-model-title {
font-size: 13px;
font-weight: 500;
color: #111827;
color: var(--tf-text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@@ -494,8 +494,8 @@
}
.tf-select-model-tag {
background: #f3f4f6;
color: #6b7280;
background: var(--tf-bg-muted);
color: var(--tf-text-secondary);
font-size: 10px;
padding: 1px 6px;
border-radius: 4px;
@@ -503,7 +503,7 @@
.tf-select-model-desc {
font-size: 11px;
color: #6b7280;
color: var(--tf-text-secondary);
line-height: 1.3;
margin-top: 2px;
display: -webkit-box;
@@ -515,10 +515,10 @@
/* Reference Variant Styles */
.tf-select-wrapper {
display: flex;
background: #fff;
background: var(--tf-bg-surface);
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
border: 1px solid #e5e7eb;
box-shadow: var(--tf-shadow-medium);
border: 1px solid var(--tf-border-color);
overflow: hidden;
/* width expands naturally since createFloating sets minWidth, not width */
width: max-content;
@@ -536,7 +536,7 @@
&.tf-select-primary-list {
width: 100%; /* Default fills the wrapper, which is minWidth-constrained by the input */
flex-shrink: 0;
background: #f9fafb;
background: var(--tf-bg-surface-alt);
}
/* When a secondary list is open, we fix the primary list to 100% of the input's width (done via absolute positioning or just keeping it wide enough) */
@@ -548,9 +548,9 @@
&.tf-select-secondary-list {
min-width: 220px;
background: #fff;
background: var(--tf-bg-surface);
padding: 12px;
border-left: 1px solid #f3f4f6;
border-left: 1px solid var(--tf-bg-muted);
animation: slideIn 0.2s ease-out;
box-sizing: border-box;
}
@@ -572,7 +572,7 @@
top: 0;
bottom: 0;
width: 1px;
background: #f0f0f0;
background: var(--tf-border-color-soft);
}
}
@@ -586,27 +586,27 @@
cursor: pointer;
text-align: left;
font-size: 13px;
color: #374151;
color: var(--tf-text-primary);
gap: 10px;
width: 100%;
transition: all 0.15s;
margin-bottom: 2px;
&:hover {
background: #f3f4f6;
background: var(--tf-bg-muted);
}
&.active {
background: #eff6ff;
color: #2563eb;
background: var(--tf-primary-soft-bg);
color: var(--tf-primary-color);
font-weight: 500;
}
&.has-children {
background: #f8fafc;
background: var(--tf-bg-hover);
margin-bottom: 4px;
&:hover {
background: #f1f5f9;
background: var(--tf-bg-active);
}
}
@@ -617,8 +617,8 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #3474ff;
background: #cedafb;
color: var(--tf-icon-color);
background: var(--tf-icon-bg);
border-radius: 5px;
padding: 3px;
box-sizing: border-box;
@@ -639,7 +639,7 @@
&-arrow {
width: 14px;
height: 14px;
color: #9ca3af;
color: var(--tf-text-muted);
}
}
@@ -656,8 +656,8 @@
align-items: center;
justify-content: center;
flex-shrink: 0;
color: #3474ff;
background: #cedafb;
color: var(--tf-icon-color);
background: var(--tf-icon-bg);
border-radius: 4px;
padding: 2px;
box-sizing: border-box;
@@ -712,8 +712,8 @@
}
.tf-parameter-type {
background: rgba(0, 0, 0, 0.06);
color: #6b7280;
background: var(--tf-bg-tag);
color: var(--tf-text-secondary);
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;

View File

@@ -10,7 +10,12 @@
} from '@codemirror/autocomplete';
import {defaultKeymap, history, historyKeymap, indentWithTab} from '@codemirror/commands';
import {javascript} from '@codemirror/lang-javascript';
import {defaultHighlightStyle, indentOnInput, indentUnit, syntaxHighlighting} from '@codemirror/language';
import {
defaultHighlightStyle,
indentOnInput,
indentUnit,
syntaxHighlighting
} from '@codemirror/language';
import {python} from '@codemirror/lang-python';
import {
Decoration,
@@ -25,8 +30,8 @@
import type {Parameter} from '#types';
import {flattenParameterCandidates} from '../utils/paramToken';
import {
createBusinessCompletionSource,
type CodeEngine,
createBusinessCompletionSource,
normalizeCodeEngine,
shouldAutoAppendCallParens
} from '../utils/codeCompletion';
@@ -230,18 +235,18 @@
function createEditorTheme() {
return EditorView.theme({
'&': {
border: '1px solid #dcdfe6',
border: '1px solid var(--tf-border-color)',
borderRadius: '6px',
backgroundColor: '#fff',
backgroundColor: 'var(--tf-bg-surface)',
fontSize: '13px'
},
'&.cm-focused': {
outline: 'none',
borderColor: '#4c82f7',
boxShadow: '0 0 0 1px rgba(76, 130, 247, 0.25)'
borderColor: 'var(--tf-primary-color)',
boxShadow: '0 0 0 1px var(--tf-primary-ghost-bg)'
},
'&.cm-editor.cm-disabled': {
backgroundColor: '#f5f7fa',
backgroundColor: 'var(--tf-bg-input-disabled)',
opacity: 0.85
},
'.cm-scroller': {
@@ -252,17 +257,17 @@
},
'.cm-content': {
padding: '8px 38px 8px 10px',
caretColor: '#1f2937'
caretColor: 'var(--tf-text-primary)'
},
'.cm-gutters': {
border: 'none',
background: 'transparent'
},
'.cm-activeLine': {
background: 'rgba(76, 130, 247, 0.06)'
background: 'var(--tf-primary-ghost-bg)'
},
'.cm-placeholder': {
color: '#c0c4cc'
color: 'var(--tf-text-muted)'
}
});
}
@@ -687,8 +692,9 @@
padding: 0 4px;
font-size: 10px;
border-radius: 4px;
color: #666;
background: rgba(255, 255, 255, 0.9);
color: var(--tf-text-secondary);
background: var(--tf-bg-surface);
border-color: var(--tf-border-color);
display: inline-flex;
align-items: center;
justify-content: center;
@@ -704,9 +710,9 @@
min-width: 20px;
padding: 0 4px;
font-size: 10px;
border-color: #d3defd;
color: #1d4ed8;
background: #f5f8ff;
border-color: var(--tf-primary-soft-border);
color: var(--tf-primary-color);
background: var(--tf-primary-soft-bg);
}
@media (max-width: 900px) {
@@ -719,9 +725,9 @@
}
:global(.code-script-button:hover) {
background: #f0f3ff;
color: #2563eb;
border-color: #d3defd;
background: var(--tf-primary-soft-bg);
color: var(--tf-primary-color);
border-color: var(--tf-primary-soft-border);
}
.code-script-panel {
@@ -729,10 +735,10 @@
max-width: 340px;
max-height: 240px;
overflow: auto;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
padding: 6px;
display: flex;
flex-direction: column;
@@ -741,14 +747,14 @@
.code-script-item {
border: none;
background: #fff;
background: var(--tf-bg-surface);
padding: 6px 8px;
text-align: left;
cursor: pointer;
border-radius: 4px;
font-size: 12px;
line-height: 1.3;
color: #333;
color: var(--tf-text-primary);
display: flex;
align-items: center;
justify-content: space-between;
@@ -756,13 +762,13 @@
}
.code-script-item:hover {
background: #f5f7ff;
color: #2563eb;
background: var(--tf-bg-surface-alt);
color: var(--tf-primary-color);
}
.code-script-item.unresolved {
background: #fff8e6;
color: #92400e;
background: var(--tf-warning-soft-bg);
color: var(--tf-warning-soft-text);
}
.code-script-item-warn {
@@ -772,8 +778,8 @@
align-items: center;
justify-content: center;
border-radius: 50%;
background: #d97706;
color: #fff;
background: var(--tf-warning-icon-color);
color: var(--tf-bg-surface);
font-size: 10px;
line-height: 1;
flex-shrink: 0;
@@ -782,38 +788,38 @@
.code-script-empty {
padding: 8px;
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
text-align: center;
}
.code-script-editor :global(.cm-special-result) {
color: #1d4ed8;
color: var(--tf-primary-color);
font-weight: 700;
}
.code-script-editor :global(.cm-template-token-valid) {
color: #1e4ed8;
background: rgba(37, 99, 235, 0.12);
color: var(--tf-primary-color);
background: var(--tf-primary-ghost-bg);
border-radius: 4px;
}
.code-script-editor :global(.cm-template-token-unresolved) {
color: #92400e;
background: rgba(217, 119, 6, 0.16);
color: var(--tf-warning-soft-text);
background: var(--tf-warning-soft-bg);
border-radius: 4px;
}
.code-script-editor :global(.cm-template-token-invalid) {
color: #b42318;
background: rgba(217, 45, 32, 0.14);
color: var(--tf-danger-soft-text);
background: var(--tf-danger-soft-bg);
border-radius: 4px;
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete) {
border: 1px solid #e6eaf2;
background: #ffffff;
border: 1px solid var(--tf-border-color);
background: var(--tf-bg-surface);
border-radius: 10px;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
box-shadow: var(--tf-shadow-medium);
padding: 6px;
min-width: 260px;
max-width: 360px;
@@ -838,29 +844,29 @@
display: flex;
align-items: center;
gap: 8px;
color: #1f2937;
color: var(--tf-text-primary);
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]) {
background: #eef4ff;
color: #1d4ed8;
background: var(--tf-primary-soft-bg);
color: var(--tf-primary-color);
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete > ul > li:hover) {
background: #f6f8fc;
background: var(--tf-bg-surface-alt);
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete .cm-completionIcon) {
width: 16px;
height: 16px;
color: #6b7280;
color: var(--tf-text-secondary);
opacity: 1;
font-size: 12px;
margin-right: 0;
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completionIcon) {
color: #2563eb;
color: var(--tf-primary-color);
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete .cm-completionLabel) {
@@ -870,14 +876,14 @@
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete .cm-completionDetail) {
margin-left: auto;
color: #94a3b8;
color: var(--tf-text-muted);
font-style: normal;
font-size: 12px;
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete .cm-completionMatchedText) {
text-decoration: none;
color: #2563eb;
color: var(--tf-primary-color);
font-weight: 700;
}
@@ -886,7 +892,7 @@
}
.code-script-editor :global(.cm-tooltip.cm-tooltip-autocomplete > ul::-webkit-scrollbar-thumb) {
background: #d6dce8;
background: var(--tf-scrollbar-thumb);
border-radius: 999px;
}

View File

@@ -158,18 +158,18 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
width: 200px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
.input-more-item {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -45,7 +45,7 @@
.none-params {
font-size: 12px;
background: #f8f8f8;
background: var(--tf-bg-muted);
height: 40px;
display: flex;
justify-content: center;
@@ -57,7 +57,7 @@
.input-header {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -156,7 +156,7 @@
display: flex;
align-items: center;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
.input-more-setting {
@@ -164,18 +164,18 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
width: 200px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
.input-more-item {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -34,7 +34,7 @@
.none-params {
font-size: 12px;
background: #f8f8f8;
background: var(--tf-bg-muted);
height: 40px;
display: flex;
justify-content: center;
@@ -46,7 +46,7 @@
.input-header {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -263,9 +263,9 @@
gap: 5px;
padding: 5px;
border-radius: 5px;
background: #fff;
border: 1px solid #eee;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color);
box-shadow: var(--tf-shadow-soft);
}
:global(.tf-node-toolbar-item) {
@@ -277,25 +277,34 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
width: 200px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
.input-item {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
.input-item-inline {
display: flex;
align-items: center;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
input[type='checkbox'] {
width: 14px;
height: 14px;
accent-color: var(--tf-primary-color);
background: var(--tf-bg-input);
border: 1px solid var(--tf-border-color-strong);
border-radius: 3px;
}
}
</style>

View File

@@ -205,21 +205,20 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
width: 200px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
.input-more-item {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}
</style>

View File

@@ -55,7 +55,7 @@
.none-params {
font-size: 12px;
background: #f8f8f8;
background: var(--tf-bg-muted);
height: 40px;
display: flex;
justify-content: center;
@@ -67,7 +67,7 @@
.input-header {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -1,12 +1,12 @@
<script lang="ts">
import { tick } from 'svelte';
import {tick} from 'svelte';
import {Button, FloatingTrigger} from '../base';
import type {Parameter} from '#types';
import {
escapeHtml,
flattenParameterCandidates,
findBackspaceTokenRange,
findTokenRangeAtCursor,
flattenParameterCandidates,
insertTextAtCursor,
parseTokenParts,
splitTokenDisplay
@@ -534,22 +534,22 @@
}
.hint-item.hint-unresolved {
background: #fff8e6;
border-color: #f6d99a;
color: #8a5a00;
background: var(--tf-warning-soft-bg);
border-color: var(--tf-warning-soft-border);
color: var(--tf-warning-soft-text);
.hint-item-icon {
color: #d97706;
color: var(--tf-warning-icon-color);
}
}
.hint-item.hint-undefined {
background: #fff1f1;
border-color: #f5c7c4;
color: #b42318;
background: var(--tf-danger-soft-bg);
border-color: var(--tf-danger-soft-border);
color: var(--tf-danger-soft-text);
.hint-item-icon {
color: #d92d20;
color: var(--tf-danger-icon-color);
}
}
@@ -570,7 +570,7 @@
border-radius: 5px;
padding: 5px 8px;
box-sizing: border-box;
color: #333;
color: var(--tf-text-primary);
pointer-events: none;
z-index: 0;
font-family: inherit;
@@ -598,7 +598,7 @@
z-index: 1;
background: transparent;
color: transparent;
caret-color: #333;
caret-color: var(--tf-text-primary);
padding-right: 36px;
font-family: inherit;
font-size: inherit;
@@ -609,7 +609,7 @@
.param-token-input::placeholder,
.param-token-textarea::placeholder {
color: #ccc;
color: var(--tf-text-muted);
}
.param-token-textarea {
@@ -630,14 +630,15 @@
padding: 0 4px;
font-size: 10px;
border-radius: 4px;
color: #666;
background: rgba(255, 255, 255, 0.9);
color: var(--tf-text-secondary);
background: var(--tf-bg-surface);
border-color: var(--tf-border-color);
}
:global(.param-token-button:hover) {
background: #f0f3ff;
color: #2563eb;
border-color: #d3defd;
background: var(--tf-primary-soft-bg);
color: var(--tf-primary-color);
border-color: var(--tf-primary-soft-border);
}
.param-token-panel {
@@ -645,10 +646,10 @@
max-width: 320px;
max-height: 220px;
overflow: auto;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
padding: 6px;
display: flex;
flex-direction: column;
@@ -657,14 +658,14 @@
.param-token-item {
border: none;
background: #fff;
background: var(--tf-bg-surface);
padding: 6px 8px;
text-align: left;
cursor: pointer;
border-radius: 4px;
font-size: 12px;
line-height: 1.3;
color: #333;
color: var(--tf-text-primary);
display: flex;
align-items: center;
justify-content: space-between;
@@ -672,13 +673,13 @@
}
.param-token-item:hover {
background: #f5f7ff;
color: #2563eb;
background: var(--tf-bg-surface-alt);
color: var(--tf-primary-color);
}
.param-token-item.unresolved {
background: #fff8e6;
color: #92400e;
background: var(--tf-warning-soft-bg);
color: var(--tf-warning-soft-text);
}
.param-token-item-warn {
@@ -687,7 +688,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
color: #d97706;
color: var(--tf-warning-icon-color);
flex-shrink: 0;
svg {
@@ -700,7 +701,7 @@
.param-token-empty {
padding: 8px;
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
text-align: center;
}
@@ -729,20 +730,20 @@
}
:global(.param-token-valid) {
background: #eaf2ff;
color: #1e4ed8;
box-shadow: inset 0 0 0 1px #c6d8ff;
background: var(--tf-primary-soft-bg);
color: var(--tf-primary-color);
box-shadow: inset 0 0 0 1px var(--tf-primary-soft-border);
}
:global(.param-token-invalid) {
background: #fff1f1;
color: #b42318;
box-shadow: inset 0 0 0 1px #f5c7c4;
background: var(--tf-danger-soft-bg);
color: var(--tf-danger-soft-text);
box-shadow: inset 0 0 0 1px var(--tf-danger-soft-border);
}
:global(.param-token-warning) {
background: #fff8e6;
color: #92400e;
box-shadow: inset 0 0 0 1px #f7d79e;
background: var(--tf-warning-soft-bg);
color: var(--tf-warning-soft-text);
box-shadow: inset 0 0 0 1px var(--tf-warning-soft-border);
}
</style>

View File

@@ -155,18 +155,18 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #ddd;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
border-radius: 5px;
width: 200px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-medium);
.input-more-item {
display: flex;
flex-direction: column;
gap: 3px;
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -47,7 +47,7 @@
.none-params {
font-size: 12px;
background: #f8f8f8;
background: var(--tf-bg-muted);
height: 40px;
display: flex;
justify-content: center;
@@ -59,7 +59,7 @@
.input-header {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
}
}

View File

@@ -3,8 +3,7 @@
import {type NodeProps, useNodesData, useSvelteFlow} from '@xyflow/svelte';
import {Button, Heading, Select} from '../base';
import RefParameterList from '../core/RefParameterList.svelte';
import {getCurrentNodeId} from '#components/utils/NodeUtils';
import {getOptions} from '#components/utils/NodeUtils';
import {getCurrentNodeId, getOptions} from '#components/utils/NodeUtils';
import {useAddParameter} from '../utils/useAddParameter.svelte';
import OutputDefList from '../core/OutputDefList.svelte';
import {onMount} from 'svelte';
@@ -152,7 +151,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}

View File

@@ -784,7 +784,7 @@
.condition-rail-title {
font-size: 13px;
color: #475569;
color: var(--tf-text-secondary);
font-weight: 500;
}
@@ -798,28 +798,28 @@
.condition-branch-row {
position: relative;
min-height: 44px;
border: 1px solid #e2e8f0;
border: 1px solid var(--tf-border-color);
border-radius: 6px;
display: flex;
align-items: center;
background: #fff;
background: var(--tf-bg-surface);
cursor: pointer;
transition: all 0.2s ease;
&:hover {
border-color: #cbd5e1;
background: #f8fafc;
border-color: var(--tf-border-color-strong);
background: var(--tf-bg-hover);
}
&.active {
border-color: #3b82f6;
box-shadow: 0 0 0 1px #3b82f6;
border-color: var(--tf-primary-color);
box-shadow: 0 0 0 1px var(--tf-primary-color);
z-index: 10;
}
&.default {
border-style: dashed;
background: #f8fafc;
background: var(--tf-bg-hover);
cursor: default; /* Disable pointer since default branch is non-selectable */
}
}
@@ -833,12 +833,12 @@
:global(.condition-branch-row .tf-input) {
font-size: 13px;
color: #475569;
color: var(--tf-text-secondary);
padding: 0;
}
:global(.condition-branch-row .tf-input:focus) {
color: #0f172a;
color: var(--tf-text-primary);
}
.condition-branch-prefix {
@@ -849,7 +849,7 @@
align-items: center;
padding-left: 12px;
padding-right: 8px;
color: #64748b;
color: var(--tf-text-secondary);
font-weight: 600;
white-space: nowrap;
}
@@ -861,7 +861,7 @@
white-space: nowrap;
text-overflow: ellipsis;
font-size: 13px;
color: #334155;
color: var(--tf-text-primary);
font-weight: 500;
}
@@ -910,9 +910,9 @@
border-radius: 4px;
font-size: 11px;
font-weight: 600;
color: #475569;
background: #f1f5f9;
border: 1px solid #cbd5e1;
color: var(--tf-text-secondary);
background: var(--tf-bg-muted);
border: 1px solid var(--tf-border-color-strong);
display: flex;
align-items: center;
justify-content: center;
@@ -921,8 +921,8 @@
box-shadow: none;
&:hover {
background: #e2e8f0;
color: #0f172a;
background: var(--tf-border-color);
color: var(--tf-text-primary);
}
}
@@ -949,9 +949,9 @@
:global(.condition-rule-add-btn) {
min-width: 140px;
background: #f8fafc;
border: 1px dashed #cbd5e1;
color: #475569;
background: var(--tf-bg-hover);
border: 1px dashed var(--tf-border-color-strong);
color: var(--tf-text-secondary);
font-size: 13px;
padding: 6px 12px;
height: 28px;
@@ -961,9 +961,9 @@
transition: all 0.2s;
&:hover {
background: #eff6ff;
border-color: #93c5fd;
color: #3b82f6;
background: var(--tf-primary-soft-bg);
border-color: var(--tf-primary-soft-border);
color: var(--tf-primary-color);
}
}
@@ -977,7 +977,7 @@
align-items: center;
gap: 8px;
/* Added to left-align the OR/AND switches properly above the left select */
color: #94a3b8;
color: var(--tf-text-muted);
}
/* Custom joiner text buttons */
@@ -987,25 +987,25 @@
padding: 2px 4px;
font-size: 12px;
font-weight: 600;
color: #94a3b8;
color: var(--tf-text-muted);
cursor: pointer;
transition: all 0.2s;
border-radius: 4px;
&:hover {
color: #64748b;
background: #f1f5f9;
color: var(--tf-text-secondary);
background: var(--tf-bg-muted);
}
&.active {
color: #3b82f6;
background: #eff6ff;
color: var(--tf-primary-color);
background: var(--tf-primary-soft-bg);
}
}
.tf-joiner-divider {
font-size: 12px;
color: #cbd5e1;
color: var(--tf-border-color-strong);
user-select: none;
}
@@ -1021,7 +1021,7 @@
padding: 0;
border: none;
background: transparent;
color: #cbd5e1;
color: var(--tf-border-color-strong);
display: flex;
align-items: center;
justify-content: center;
@@ -1035,8 +1035,8 @@
}
&:hover {
background: #fee2e2;
color: #ef4444;
background: var(--tf-danger-soft-bg);
color: var(--tf-danger-color);
}
}
@@ -1059,6 +1059,20 @@
min-width: 0;
}
:global(.condition-simple-rule-row .tf-select-input),
:global(.condition-simple-rule-row .tf-mixed-input-root),
:global(.condition-simple-rule-row .tf-input),
:global(.condition-simple-rule-row .tf-textarea) {
background: var(--tf-bg-input);
border-color: var(--tf-border-color-strong);
color: var(--tf-text-primary);
}
:global(.condition-simple-rule-row .tf-select-input:hover),
:global(.condition-simple-rule-row .tf-mixed-input-root:hover) {
border-color: var(--tf-border-color-strong);
}
:global(.condition-icon-btn) {
width: 26px;
height: 26px;
@@ -1066,7 +1080,7 @@
border-color: transparent;
border-radius: 4px;
background: transparent;
color: #64748b;
color: var(--tf-text-secondary);
padding: 0;
display: inline-flex;
align-items: center;
@@ -1081,33 +1095,33 @@
}
:global(.condition-icon-btn:hover:not(:disabled)) {
background: #cbd5e1;
color: #0f172a;
background: var(--tf-border-color-strong);
color: var(--tf-text-primary);
}
:global(.condition-icon-btn.danger) {
color: #ef4444;
color: var(--tf-danger-color);
}
:global(.condition-icon-btn.danger:hover:not(:disabled)) {
background: #fee2e2;
color: #b91c1c;
background: var(--tf-danger-soft-bg);
color: var(--tf-danger-hover);
}
:global(.condition-icon-btn:disabled),
:global(.condition-icon-btn[disabled]) {
color: #cbd5e1;
color: var(--tf-border-color-strong);
background: transparent;
cursor: not-allowed;
}
.condition-default-tip {
color: #64748b;
color: var(--tf-text-secondary);
font-size: 12px;
padding: 8px 10px;
border-radius: 6px;
background: #f1f5f9;
border: 1px dashed #cbd5e1;
background: var(--tf-bg-muted);
border: 1px dashed var(--tf-border-color-strong);
text-align: center;
}
@@ -1126,18 +1140,18 @@
flex-direction: column;
gap: 10px;
padding: 10px;
background: #fff;
border: 1px solid #e2e8f0;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color);
border-radius: 6px;
width: 180px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
box-shadow: var(--tf-shadow-medium);
.input-more-item {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 12px;
color: #64748b;
color: var(--tf-text-secondary);
}
}

View File

@@ -113,7 +113,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}

View File

@@ -232,7 +232,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}
@@ -255,7 +255,7 @@
.slider-container span {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
display: flex;
justify-content: space-between;
align-items: center;
@@ -264,7 +264,7 @@
input[type="range"] {
width: 100%;
height: 4px;
background: #ddd;
background: var(--tf-slider-track-bg);
border-radius: 2px;
outline: none;
-webkit-appearance: none;
@@ -274,7 +274,7 @@
-webkit-appearance: none;
width: 14px;
height: 14px;
background: #007bff;
background: var(--tf-slider-thumb-bg);
border-radius: 50%;
cursor: pointer;
}

View File

@@ -271,15 +271,15 @@
.http-section {
margin: 10px 0;
padding: 10px;
border: 1px solid #e6eaf2;
border: 1px solid var(--tf-border-color);
border-radius: 8px;
background: #fafcff;
background: var(--tf-bg-surface-alt);
}
.section-title {
font-size: 12px;
line-height: 1.3;
color: #6b7280;
color: var(--tf-text-secondary);
font-weight: 600;
margin-bottom: 8px;
}
@@ -314,17 +314,17 @@
box-sizing: border-box;
padding: 5px 10px;
border-radius: 999px;
border: 1px solid #dbe3f3;
background: #fff;
color: #4b5563;
border: 1px solid var(--tf-border-color-strong);
background: var(--tf-bg-surface);
color: var(--tf-text-secondary);
cursor: pointer;
transition: all 0.15s ease;
}
label.active {
background: #eef4ff;
border-color: #c7d8ff;
color: #1d4ed8;
background: var(--tf-primary-soft-bg);
border-color: var(--tf-primary-soft-border);
color: var(--tf-primary-color);
}
:global(input[type='radio']) {

View File

@@ -170,7 +170,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}

View File

@@ -285,7 +285,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}
@@ -308,7 +308,7 @@
.slider-container span {
font-size: 12px;
color: #666;
color: var(--tf-text-secondary);
display: flex;
justify-content: space-between;
align-items: center;
@@ -316,18 +316,18 @@
.llm-setting {
width: 200px;
background: #fff;
background: var(--tf-bg-surface);
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border: 1px solid #ddd;
box-shadow: var(--tf-shadow-medium);
border: 1px solid var(--tf-border-color-strong);
}
input[type="range"] {
width: 100%;
height: 4px;
background: #ddd;
background: var(--tf-slider-track-bg);
border-radius: 2px;
outline: none;
-webkit-appearance: none;
@@ -337,9 +337,8 @@
-webkit-appearance: none;
width: 14px;
height: 14px;
background: #007bff;
background: var(--tf-slider-thumb-bg);
border-radius: 50%;
cursor: pointer;
}
</style>

View File

@@ -81,15 +81,15 @@
content: '循环体';
width: 100px;
height: 20px;
background: #000;
color: #fff;
background: var(--tf-bg-surface-alt);
color: var(--tf-loop-handle-text);
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--tf-border-color-strong);
border-radius: 4px;
}
}
</style>

View File

@@ -156,7 +156,7 @@
.setting-title {
font-size: 12px;
color: #999;
color: var(--tf-text-muted);
margin-bottom: 4px;
margin-top: 10px;
}

View File

@@ -50,10 +50,9 @@
padding: 3px;
&:hover {
background: #eee;
background: var(--tf-bg-hover);
border: 1px solid transparent;
}
}
</style>

View File

@@ -3,8 +3,9 @@
align-items: center;
justify-content: center;
gap: 2px;
background: #fff;
border: 1px solid #ccc;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color-strong);
color: var(--tf-text-primary);
cursor: pointer;
border-radius: 5px;
padding: 5px;
@@ -25,11 +26,11 @@
.tf-btn.tf-btn-primary {
background: var(--tf-primary-color);
color: #fff;
color: var(--tf-loop-handle-text);
&:hover {
border: 1px solid #ccc;
background: #3a6fe3;
border: 1px solid var(--tf-border-color-strong);
background: var(--tf-primary-color-hover);
}
}
@@ -37,7 +38,9 @@
.tf-input, .tf-textarea {
display: flex;
border-radius: 5px;
border: 1px solid #ccc;
border: 1px solid var(--tf-border-color-strong);
background: var(--tf-bg-input);
color: var(--tf-text-primary);
padding: 5px 8px;
box-sizing: border-box;
resize: vertical;
@@ -46,21 +49,21 @@
overflow-y: hidden;
&::placeholder {
color: #ccc;
color: var(--tf-text-muted);
font-size: 12px;
}
// 获得焦点时的样式
&:focus {
border-color: var(--tf-primary-color);
box-shadow: 0 0 5px rgba(81, 203, 238, .2);
box-shadow: var(--tf-focus-shadow);
}
// 禁用时的样式
&[disabled] {
background-color: #f0f0f0;
background-color: var(--tf-bg-input-disabled);
cursor: not-allowed;
color: #aaa;
color: var(--tf-text-disabled);
}
}
@@ -68,26 +71,26 @@
.tf-select {
&-input {
display: flex;
border: 1px solid #e5e7eb;
border: 1px solid var(--tf-border-color);
padding: 4px 10px;
border-radius: 6px;
font-size: 13px;
justify-content: space-between;
align-items: center;
cursor: pointer;
background: #fff;
background: var(--tf-bg-input);
height: 32px;
transition: all 0.2s;
width: 100%;
color: #111827;
color: var(--tf-text-primary);
&:hover {
border-color: #d1d5db;
border-color: var(--tf-border-color-strong);
}
&:focus, &.active {
border-color: #2563eb;
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
border-color: var(--tf-primary-color);
box-shadow: var(--tf-focus-shadow);
}
&-value {
@@ -105,13 +108,13 @@
display: flex;
width: 16px;
height: 16px;
color: #6b7280;
color: var(--tf-text-secondary);
flex-shrink: 0;
margin-left: 4px;
}
&-placeholder {
color: #9ca3af;
color: var(--tf-text-muted);
}
}
@@ -133,7 +136,7 @@
padding: 5px;
border-radius: 5px;
border: none;
background: #F4F4F5;
background: var(--tf-bg-muted);
.tf-tabs-item {
flex-grow: 1;
@@ -144,14 +147,14 @@
align-items: center;
justify-content: center;
font-size: 14px;
color: #808088;
color: var(--tf-text-secondary);
}
.tf-tabs-item.active {
background: #fff;
color: #333;
background: var(--tf-bg-surface);
color: var(--tf-text-primary);
font-weight: 500;
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.15);
box-shadow: var(--tf-shadow-soft);
}
}
@@ -160,7 +163,7 @@ h3.tf-heading {
font-size: 14px;
margin-top: 2px;
margin-bottom: 3px;
color: #333;
color: var(--tf-text-primary);
}
@@ -181,8 +184,8 @@ h3.tf-heading {
display: flex;
width: 26px;
height: 26px;
color: #2563EB;
background: #cedafb;
color: var(--tf-icon-color);
background: var(--tf-icon-bg);
border-radius: 5px;
padding: 3px;
justify-content: center;
@@ -192,7 +195,7 @@ h3.tf-heading {
svg {
width: 22px;
height: 22px;
color: #3474ff;
color: var(--tf-icon-color);
}
}
@@ -208,7 +211,7 @@ h3.tf-heading {
&-description {
font-size: 12px;
margin: 10px 0;
color: #999;
color: var(--tf-text-muted);
}
}
}

View File

@@ -18,7 +18,7 @@
&::after {
content: ' ';
background: #2563EB;
background: var(--tf-primary-color);
width: 8px;
height: 8px;
border-radius: 100%;
@@ -36,12 +36,12 @@
div.loop_handle_wrapper {
&::after {
content: '循环体';
background: #2563EB;
background: var(--tf-primary-color);
width: 100px;
height: 20px;
border-radius: 0;
display: flex;
color: #fff;
color: var(--tf-loop-handle-text);
justify-content: center;
align-items: center;
}
@@ -60,17 +60,17 @@
border-radius: 5px;
top: -2px;
left: -2px;
border: 1px solid #ccc;
border: 1px solid var(--tf-node-outline-color);
height: calc(100% + 2px);
width: calc(100% + 2px);
}
&:hover {
border: 3px solid #bacaef7d;
border: 3px solid var(--tf-node-hover-border);
}
&.selectable.selected {
border: 3px solid #bacaef7d;
border: 3px solid var(--tf-node-hover-border);
box-shadow: var(--xy-node-boxshadow-selected);
}
@@ -88,7 +88,7 @@
.tf-node-wrapper {
border-radius: 5px;
min-width: 300px;
background: #fff;
background: var(--tf-bg-surface);
&-body {
padding: 10px;
@@ -114,10 +114,10 @@
}
&-container {
background: #fff;
border: 1px solid #eee;
background: var(--tf-bg-surface);
border: 1px solid var(--tf-border-color);
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
box-shadow: var(--tf-shadow-soft);
padding: 10px;
width: fit-content;
@@ -147,11 +147,11 @@
svg {
width: 20px;
height: 20px;
fill: #2563EB;
fill: var(--tf-primary-color);
}
&:hover {
background: #f1f1f1;
background: var(--tf-bg-hover);
}
}
}

View File

@@ -1,14 +1,144 @@
:root,
:root .tf-theme-light {
--tf-primary-color: #2563EB;
--tf-primary-color: #2563eb;
--tf-primary-color-hover: #3a6fe3;
--tf-primary-soft-bg: #eff6ff;
--tf-primary-soft-border: #bfdbfe;
--tf-primary-ghost-bg: rgba(37, 99, 235, 0.08);
--tf-danger-color: #ef4444;
--tf-danger-hover: #dc2626;
--tf-danger-soft-bg: #fff1f1;
--tf-danger-soft-border: #f5c7c4;
--tf-danger-soft-text: #b42318;
--tf-danger-icon-color: #d92d20;
--tf-warning-soft-bg: #fff8e6;
--tf-warning-soft-border: #f7d79e;
--tf-warning-soft-text: #92400e;
--tf-warning-icon-color: #d97706;
--tf-bg-canvas: #f8fafc;
--tf-bg-surface: #ffffff;
--tf-bg-surface-alt: #f9fafb;
--tf-bg-muted: #f3f4f6;
--tf-bg-hover: #f1f5f9;
--tf-bg-active: #e2e8f0;
--tf-bg-input: #ffffff;
--tf-bg-input-disabled: #f3f4f6;
--tf-bg-tag: rgba(0, 0, 0, 0.06);
--tf-border-color: #e5e7eb;
--tf-border-color-strong: #d1d5db;
--tf-border-color-soft: #f3f4f6;
--tf-node-outline-color: #d1d5db;
--tf-node-hover-border: rgba(186, 202, 239, 0.49);
--tf-text-primary: #111827;
--tf-text-secondary: #6b7280;
--tf-text-muted: #9ca3af;
--tf-text-disabled: #9ca3af;
--tf-icon-bg: #cedafb;
--tf-icon-color: #3474ff;
--tf-loop-handle-text: #ffffff;
--tf-shadow-soft: 0 2px 4px rgba(0, 0, 0, 0.08);
--tf-shadow-medium: 0 10px 25px rgba(0, 0, 0, 0.15);
--tf-focus-shadow: 0 0 0 2px rgba(37, 99, 235, 0.12);
--tf-tip-bg: #0f172a;
--tf-tip-text: #f8fafc;
--tf-scrollbar-thumb: #d6dce8;
--tf-slider-track-bg: #d1d5db;
--tf-slider-thumb-bg: var(--tf-primary-color);
--xy-node-boxshadow-selected: 0 0 0 1px var(--tf-primary-color);
--xy-handle-background-color: var(--tf-primary-color);
--xy-handle-border-color: var(--tf-bg-surface);
--xy-background-color: var(--tf-bg-canvas);
--xy-background-pattern-dots-color: #d1d5db;
--xy-background-pattern-lines-color: #e5e7eb;
--xy-background-pattern-cross-color: #e2e8f0;
--xy-edge-stroke: #94a3b8;
--xy-edge-stroke-selected: var(--tf-primary-color);
--xy-controls-button-background-color: var(--tf-bg-surface);
--xy-controls-button-background-color-hover: var(--tf-bg-hover);
--xy-controls-button-color: var(--tf-text-secondary);
--xy-controls-button-color-hover: var(--tf-text-primary);
--xy-controls-button-border-color: var(--tf-border-color);
--xy-minimap-background-color: var(--tf-bg-surface);
--xy-minimap-mask-background-color: rgba(241, 245, 249, 0.68);
--xy-minimap-node-background-color: #cbd5e1;
--xy-edge-label-background-color: var(--tf-bg-surface);
--xy-edge-label-color: var(--tf-text-primary);
}
//the dark theme variables
:root .tf-theme-dark {
--tf-primary-color: #60a5fa;
--tf-primary-color-hover: #93c5fd;
--tf-primary-soft-bg: rgba(96, 165, 250, 0.18);
--tf-primary-soft-border: rgba(96, 165, 250, 0.35);
--tf-primary-ghost-bg: rgba(96, 165, 250, 0.12);
--tf-danger-color: #f87171;
--tf-danger-hover: #ef4444;
--tf-danger-soft-bg: rgba(248, 113, 113, 0.16);
--tf-danger-soft-border: rgba(248, 113, 113, 0.28);
--tf-danger-soft-text: #fca5a5;
--tf-danger-icon-color: #f87171;
--tf-warning-soft-bg: rgba(217, 119, 6, 0.2);
--tf-warning-soft-border: rgba(217, 119, 6, 0.35);
--tf-warning-soft-text: #fbbf24;
--tf-warning-icon-color: #f59e0b;
--tf-bg-canvas: #0b1220;
--tf-bg-surface: #111827;
--tf-bg-surface-alt: #1f2937;
--tf-bg-muted: #273449;
--tf-bg-hover: #334155;
--tf-bg-active: #3b4b63;
--tf-bg-input: #0f172a;
--tf-bg-input-disabled: #0b1324;
--tf-bg-tag: rgba(148, 163, 184, 0.2);
--tf-border-color: #334155;
--tf-border-color-strong: #475569;
--tf-border-color-soft: #263449;
--tf-node-outline-color: #475569;
--tf-node-hover-border: rgba(96, 165, 250, 0.38);
--tf-text-primary: #e5e7eb;
--tf-text-secondary: #cbd5e1;
--tf-text-muted: #94a3b8;
--tf-text-disabled: #64748b;
--tf-icon-bg: rgba(96, 165, 250, 0.2);
--tf-icon-color: #93c5fd;
--tf-loop-handle-text: #f8fafc;
--tf-shadow-soft: 0 2px 8px rgba(2, 6, 23, 0.35);
--tf-shadow-medium: 0 10px 25px rgba(2, 6, 23, 0.48);
--tf-focus-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);
--tf-tip-bg: #020617;
--tf-tip-text: #e2e8f0;
--tf-scrollbar-thumb: #475569;
--tf-slider-track-bg: #475569;
--tf-slider-thumb-bg: #93c5fd;
--xy-node-boxshadow-selected: 0 0 0 1px var(--tf-primary-color);
--xy-handle-background-color: var(--tf-primary-color);
--xy-handle-border-color: var(--tf-bg-canvas);
--xy-background-color: var(--tf-bg-canvas);
--xy-background-pattern-dots-color: #334155;
--xy-background-pattern-lines-color: #334155;
--xy-background-pattern-cross-color: #334155;
--xy-edge-stroke: #64748b;
--xy-edge-stroke-selected: #93c5fd;
--xy-controls-button-background-color: var(--tf-bg-surface);
--xy-controls-button-background-color-hover: var(--tf-bg-hover);
--xy-controls-button-color: var(--tf-text-secondary);
--xy-controls-button-color-hover: var(--tf-text-primary);
--xy-controls-button-border-color: var(--tf-border-color);
--xy-minimap-background-color: var(--tf-bg-surface);
--xy-minimap-mask-background-color: rgba(15, 23, 42, 0.7);
--xy-minimap-node-background-color: #475569;
--xy-edge-label-background-color: var(--tf-bg-surface);
--xy-edge-label-color: var(--tf-text-primary);
}

View File

@@ -0,0 +1,70 @@
import {beforeEach, describe, expect, it} from 'vitest';
import {componentName} from './consts';
import {Tinyflow} from './Tinyflow';
describe('tinyflow theme', () => {
beforeEach(() => {
document.body.innerHTML = '';
});
it('should use light theme by default', () => {
const container = document.createElement('div');
document.body.append(container);
const tinyflow = new Tinyflow({
element: container
});
const tinyflowEl = container.querySelector(componentName);
expect(tinyflowEl).toBeTruthy();
expect(tinyflowEl?.classList.contains('tf-theme-light')).toBe(true);
expect(tinyflowEl?.classList.contains('tf-theme-dark')).toBe(false);
tinyflow.destroy();
});
it('should toggle theme class without remount', () => {
const container = document.createElement('div');
document.body.append(container);
const tinyflow = new Tinyflow({
element: container,
theme: 'dark'
});
const tinyflowEl = container.querySelector(componentName);
expect(tinyflowEl?.classList.contains('tf-theme-dark')).toBe(true);
tinyflow.setTheme('light');
expect(tinyflowEl?.classList.contains('tf-theme-light')).toBe(true);
expect(tinyflowEl?.classList.contains('tf-theme-dark')).toBe(false);
tinyflow.destroy();
});
it('should keep theme when data is reset', () => {
const container = document.createElement('div');
document.body.append(container);
const tinyflow = new Tinyflow({
element: container,
theme: 'dark'
});
const firstRenderEl = container.querySelector(componentName);
tinyflow.setData({
nodes: [],
edges: []
});
const secondRenderEl = container.querySelector(componentName);
expect(firstRenderEl).toBeTruthy();
expect(secondRenderEl).toBeTruthy();
expect(secondRenderEl).not.toBe(firstRenderEl);
expect(secondRenderEl?.classList.contains('tf-theme-dark')).toBe(true);
tinyflow.destroy();
});
});

View File

@@ -2,6 +2,7 @@ import type {Snippet} from 'svelte';
import type {Node, useSvelteFlow} from '@xyflow/svelte';
export type TinyflowData = Partial<ReturnType<ReturnType<typeof useSvelteFlow>['toObject']>>;
export type TinyflowTheme = 'light' | 'dark';
export type SelectItem = {
value: number | string;
@@ -82,6 +83,7 @@ export type CustomNode = {
export type TinyflowOptions = {
element: string | Element;
theme?: TinyflowTheme;
data?: TinyflowData | string;
provider?: {
llm?: () => SelectItem[] | Promise<SelectItem[]>;

View File

@@ -5,7 +5,7 @@
<script setup lang="ts">
import {Tinyflow as TinyflowNative, TinyflowOptions} from '@tinyflow-ai/ui';
import '@tinyflow-ai/ui/dist/index.css';
import {onMounted, onUnmounted, ref} from 'vue';
import {onMounted, onUnmounted, ref, watch} from 'vue';
const props = defineProps<
{
@@ -55,6 +55,15 @@ onUnmounted(() => {
}
});
watch(
() => props.theme,
(theme) => {
if (tinyflow) {
tinyflow.setTheme(theme || 'light');
}
}
);
const getData = () => {
if (tinyflow) {
return tinyflow.getData();
@@ -71,8 +80,17 @@ const getInstance = () => {
return null;
};
const focusNode = async (nodeId: string, options?: { duration?: number; zoom?: number }) => {
if (tinyflow) {
return tinyflow.focusNode(nodeId, options);
}
console.warn('Tinyflow instance is not initialized');
return false;
};
defineExpose({
getData,
getInstance
getInstance,
focusNode
});
</script>