Menu
Public repository / 439f0dcabf5cdf2b120c7724be895cf1df30507f
AkurAI-Framework / site/frontend/ai/components/input/parameter_slider.js
Latest change 63ae119f1bdd5ddffd3f9a2b3b3216aa9d21449b - feat(ai): Input component batch — option_list, parameter_slider, preferences_panel, question_flow by Ólafur Búi Ólafsson
/**
* Parameter Slider — tool-UI input component.
* Payload: { label, min, max, step?, value, unit? }
* Receipt: { component: 'parameter_slider', value: number }
*/
function emit(el, detail) {
el.dispatchEvent(new CustomEvent('toolui:input', { bubbles: true, detail }));
}
export const def = {
name: 'parameter_slider',
category: 'Input',
title: 'Parameter Slider',
match(p) {
return (
p != null &&
typeof p.min === 'number' &&
typeof p.max === 'number' &&
typeof p.value === 'number'
);
},
render(p, ctx) {
const { label = '', min, max, step = 1, value, unit = '' } = p;
let current = value;
function fmt(v) {
return unit ? `${v} ${unit}` : String(v);
}
const root = document.createElement('div');
root.className = 'card';
root.style.cssText = 'display:grid;gap:14px;max-width:420px;';
// Header row: label + live value badge
const head = document.createElement('div');
head.style.cssText =
'display:flex;align-items:center;justify-content:space-between;gap:12px;';
const labelEl = document.createElement('span');
labelEl.style.fontWeight = '600';
labelEl.textContent = label;
head.appendChild(labelEl);
const display = document.createElement('span');
display.className = 'badge badge-ok';
display.style.fontFamily = 'var(--mono)';
display.textContent = fmt(value);
head.appendChild(display);
root.appendChild(head);
// Slider
const slider = document.createElement('input');
slider.type = 'range';
slider.min = String(min);
slider.max = String(max);
slider.step = String(step);
slider.value = String(value);
slider.style.width = '100%';
slider.addEventListener('input', () => {
current = Number(slider.value);
display.textContent = fmt(current);
});
root.appendChild(slider);
// Min / max range labels
const rangeRow = document.createElement('div');
rangeRow.style.cssText =
'display:flex;justify-content:space-between;font-size:12px;' +
'color:var(--muted);margin-top:-8px;';
const minLabel = document.createElement('span');
minLabel.textContent = fmt(min);
const maxLabel = document.createElement('span');
maxLabel.textContent = fmt(max);
rangeRow.appendChild(minLabel);
rangeRow.appendChild(maxLabel);
root.appendChild(rangeRow);
// Apply button
const btn = document.createElement('button');
btn.className = 'btn btn-primary btn-sm';
btn.textContent = 'Apply';
btn.addEventListener('click', () => {
const receipt = { component: 'parameter_slider', value: current };
if (ctx && typeof ctx.sendReceipt === 'function') ctx.sendReceipt(receipt);
emit(root, receipt);
btn.disabled = true;
btn.textContent = 'Applied ✓';
});
root.appendChild(btn);
return root;
},
example: {
label: 'Temperature',
min: 0,
max: 2,
step: 0.1,
value: 0.7,
unit: ''
}
};