diff --git a/src/backend/base/langflow/components/models/openai.py b/src/backend/base/langflow/components/models/openai.py index 92d216250..60f960a73 100644 --- a/src/backend/base/langflow/components/models/openai.py +++ b/src/backend/base/langflow/components/models/openai.py @@ -70,7 +70,9 @@ class OpenAIModelComponent(LCModelComponent): advanced=False, value="OPENAI_API_KEY", ), - SliderInput(name="temperature", display_name="Temperature", value=0.1, range_spec=RangeSpec(min=0, max=1)), + SliderInput( + name="temperature", display_name="Temperature", value=0.1, range_spec=RangeSpec(min=0, max=2, step=0.01) + ), IntInput( name="seed", display_name="Seed", diff --git a/src/frontend/src/App.css b/src/frontend/src/App.css index 2cd6f1d45..f099a3aba 100644 --- a/src/frontend/src/App.css +++ b/src/frontend/src/App.css @@ -191,3 +191,9 @@ code { .ag-cell-wrapper > *:not(.ag-cell-value):not(.ag-group-value) { --ag-internal-calculated-line-height: none !important; } + +.arrow-hide::-webkit-inner-spin-button, +.arrow-hide::-webkit-outer-spin-button { + appearance: none; + margin: 0; +} diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/components/slider-labels.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/components/slider-labels.tsx new file mode 100644 index 000000000..e85aa45b3 --- /dev/null +++ b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/components/slider-labels.tsx @@ -0,0 +1,46 @@ +import IconComponent from "@/components/common/genericIconComponent"; + +export const SliderLabels = ({ + minLabel, + maxLabel, + minLabelIcon, + maxLabelIcon, +}: { + minLabel: string; + maxLabel: string; + minLabelIcon: string; + maxLabelIcon: string; +}) => { + return ( + <> +
+
+
+
+ + {maxLabel} + +
+
+ + ); +}; diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/helpers/build-color-by-name.ts b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/helpers/build-color-by-name.ts new file mode 100644 index 000000000..962c6c386 --- /dev/null +++ b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/helpers/build-color-by-name.ts @@ -0,0 +1,30 @@ +export const buildColorByName = ( + accentIndigoForeground: string, + accentPinkForeground: string, + percentage: number, +) => { + const startHue = parseInt(accentIndigoForeground.split(" ")[0]); + const endHue = parseInt(accentPinkForeground.split(" ")[0]); + + const startSaturation = parseInt( + accentIndigoForeground.split(" ")[1].replace("%", ""), + ); + const endSaturation = parseInt( + accentPinkForeground.split(" ")[1].replace("%", ""), + ); + + const startLightness = parseInt( + accentIndigoForeground.split(" ")[2].replace("%", ""), + ); + const endLightness = parseInt( + accentPinkForeground.split(" ")[2].replace("%", ""), + ); + + const hue = startHue + (endHue - startHue) * (percentage / 100); + const saturation = + startSaturation + (endSaturation - startSaturation) * (percentage / 100); + const lightness = + startLightness + (endLightness - startLightness) * (percentage / 100); + + return `hsl(${hue}, ${saturation}%, ${lightness}%)`; +}; diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/utils/get-min-max-value.ts b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/helpers/get-min-max-value.ts similarity index 100% rename from src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/utils/get-min-max-value.ts rename to src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/helpers/get-min-max-value.ts diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx index 522ef87b5..3bf71dcc8 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/index.tsx @@ -1,12 +1,13 @@ -import IconComponent from "@/components/common/genericIconComponent"; -import { getMinOrMaxValue } from "@/components/core/parameterRenderComponent/components/sliderComponent/utils/get-min-max-value"; +import { getMinOrMaxValue } from "@/components/core/parameterRenderComponent/components/sliderComponent/helpers/get-min-max-value"; import { InputProps } from "@/components/core/parameterRenderComponent/types"; import { Case } from "@/shared/components/caseComponent"; import { useDarkStore } from "@/stores/darkStore"; import { SliderComponentType } from "@/types/components"; import * as SliderPrimitive from "@radix-ui/react-slider"; import clsx from "clsx"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; +import { SliderLabels } from "./components/slider-labels"; +import { buildColorByName } from "./helpers/build-color-by-name"; const THRESHOLDS = [0.25, 0.5, 0.75, 1]; const BACKGROUND_COLORS = ["#4f46e5", "#7c3aed", "#a21caf", "#c026d3"]; @@ -26,10 +27,13 @@ const DEFAULT_SLIDER_BUTTONS_OPTIONS = [ ]; const MIN_LABEL = "Precise"; -const MAX_LABEL = "Wild"; +const MAX_LABEL = "Creative"; const MIN_LABEL_ICON = "pencil-ruler"; const MAX_LABEL_ICON = "palette"; +const DEFAULT_ACCENT_PINK_FOREGROUND_COLOR = "333 71% 51%"; +const DEFAULT_ACCENT_INDIGO_FOREGROUND_COLOR = "243 75% 59%"; + type ColorType = "background" | "text"; export default function SliderComponent({ @@ -43,7 +47,6 @@ export default function SliderComponent({ maxLabelIcon = MAX_LABEL_ICON, sliderButtons = false, sliderButtonsOptions = DEFAULT_SLIDER_BUTTONS_OPTIONS, - sliderInput = false, handleOnNewValue, }: InputProps): JSX.Element { const min = rangeSpec?.min ?? -2; @@ -60,7 +63,7 @@ export default function SliderComponent({ maxLabel = maxLabel || MAX_LABEL; const valueAsNumber = getMinOrMaxValue(Number(value), min, max); - const step = rangeSpec?.step ?? 0.1; + const step = rangeSpec?.step ?? 0.01; useEffect(() => { if (disabled && value !== "") { @@ -134,19 +137,102 @@ export default function SliderComponent({ return getColor(optionValue, normalizedValue, "text"); }; + const [isGrabbing, setIsGrabbing] = useState(false); + const [isEditing, setIsEditing] = useState(false); + const [inputValue, setInputValue] = useState(valueAsNumber.toFixed(2)); + + const handleInputChange = (e: React.ChangeEvent) => { + setInputValue(e.target.value); + }; + + const handleInputBlur = () => { + const newValue = parseFloat(inputValue); + if (!isNaN(newValue)) { + const clampedValue = Math.min(Math.max(newValue, min), max); + handleOnNewValue({ value: clampedValue }); + } + setIsEditing(false); + setInputValue(valueAsNumber.toFixed(2)); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + handleInputBlur(); + } else if (e.key === "Escape") { + setIsEditing(false); + setInputValue(valueAsNumber.toFixed(2)); + } + }; + + const percentage = ((valueAsNumber - min) / (max - min)) * 100; + + if (isDark) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + + const accentIndigoForeground = getComputedStyle( + document.documentElement, + ).getPropertyValue("--accent-indigo-foreground"); + + const accentPinkForeground = getComputedStyle( + document.documentElement, + ).getPropertyValue("--accent-pink-foreground"); + + const getThumbColor = (percentage) => { + if (accentIndigoForeground && accentPinkForeground) { + return buildColorByName( + accentIndigoForeground, + accentPinkForeground, + percentage, + ); + } + return buildColorByName( + DEFAULT_ACCENT_INDIGO_FOREGROUND_COLOR, + DEFAULT_ACCENT_PINK_FOREGROUND_COLOR, + percentage, + ); + }; + + const ringClassInputClass = "ring-[1px] ring-slider-input-border"; + return (
- -
- +
+
- {valueAsNumber.toFixed(2)} - + {isEditing ? ( + + ) : ( + { + setIsEditing(true); + setInputValue(valueAsNumber.toFixed(2)); + }} + data-testid={`default_slider_display_value${editNode ? "_advanced" : ""}`} + className="relative bottom-[1px] font-mono text-sm hover:cursor-text" + > + {valueAsNumber.toFixed(2)} + + )} +
- +
- + setIsGrabbing(true)} + onPointerUp={() => setIsGrabbing(false)} + style={{ + backgroundColor: getThumbColor(percentage), + }} /> - {sliderInput && ( - handleChange([parseFloat(e.target.value)])} - className={clsx( - "primary-input ml-2 h-10 w-16 rounded-md border px-2 py-1 text-sm arrow-hide", - )} - min={min} - max={max} - step={step} - disabled={disabled} - /> - )}
{sliderButtons && ( @@ -223,28 +307,12 @@ export default function SliderComponent({
)} -
-
-
-
- - {maxLabel} - -
-
+
); } diff --git a/src/frontend/src/style/applies.css b/src/frontend/src/style/applies.css index 661a49f48..72f388a17 100644 --- a/src/frontend/src/style/applies.css +++ b/src/frontend/src/style/applies.css @@ -1272,6 +1272,10 @@ .playground-btn-flow-toolbar { @apply relative inline-flex h-8 w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold transition-all duration-500 ease-in-out; } + + .input-slider-text { + @apply absolute bottom-[4.2rem] right-3 w-14 cursor-text rounded-sm px-2 py-[1px] text-center hover:ring-[1px] hover:ring-slider-input-border; + } } /* Gradient background */ diff --git a/src/frontend/src/style/index.css b/src/frontend/src/style/index.css index 58c46731c..156a39add 100644 --- a/src/frontend/src/style/index.css +++ b/src/frontend/src/style/index.css @@ -162,6 +162,8 @@ --tool-mode-gradient-1: #f480ff; --tool-mode-gradient-2: #ff3276; + + --slider-input-border: #d4d4d8; } .dark { @@ -313,5 +315,7 @@ --datatype-orange-foreground: 30.7 97.2% 72.4%; --node-ring: 240 6% 90%; + + --slider-input-border: #d4d4d8; } } diff --git a/src/frontend/tailwind.config.mjs b/src/frontend/tailwind.config.mjs index 3455040f0..b3b867103 100644 --- a/src/frontend/tailwind.config.mjs +++ b/src/frontend/tailwind.config.mjs @@ -256,6 +256,7 @@ const config = { "holo-frost": "hsl(var(--holo-frost))", "terminal-green": "hsl(var(--terminal-green))", "cosmic-void": "hsl(var(--cosmic-void))", + "slider-input-border": "var(--slider-input-border)", }, borderRadius: { lg: `var(--radius)`,