Appearance
Example: Temperature Converter
examplejs
import { compose } from 'paintor'
import { TemperatureConverter } from './components/TemperatureConverter.js'
compose(
TemperatureConverter({ scales: ['celsius', 'fahrenheit', 'kelvin'] })
).paint('#temperature-converter')
js
import { template } from 'paintor'
import { TemperatureInput } from './TemperatureInput.js'
export function TemperatureConverter({ scales }) {
const temperatureInputs = []
for (const scale of scales) {
temperatureInputs.push(TemperatureInput(scale))
}
return template(temperatureInputs)
}
js
import { state, template } from 'paintor'
const temperaturesState = state({
celsius: '',
fahrenheit: '',
kelvin: ''
})
const scaleNames = {
celsius: 'Celsius',
fahrenheit: 'Fahrenheit',
kelvin: 'Kelvin'
}
const converters = {
celsius: {
fahrenheit(celsius) {
return (celsius * 9 / 5) + 32
},
kelvin(celsius) {
return celsius + 273.15
}
},
fahrenheit: {
celsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9
},
kelvin(fahrenheit) {
return ((fahrenheit - 32) * 5 / 9) + 273.15
}
},
kelvin: {
celsius(kelvin) {
return kelvin - 273.15
},
fahrenheit(kelvin) {
return ((kelvin - 273.15) * 9 / 5) + 32
},
}
}
function getConverterFunction(fromScale, toScale) {
const converterFn = converters[fromScale][toScale]
if (!converterFn) {
throw new Error(`There is no converter function to convert ${fromScale} to ${toScale}`)
}
return converterFn
}
function convert(fromScale, toScale, temperature) {
const input = parseFloat(temperature)
if (Number.isNaN(input)) {
return ''
}
const output = getConverterFunction(fromScale, toScale)(input)
const rounded = Math.round(output * 1000) / 1000
return rounded.toString()
}
export function TemperatureInput(fromScale) {
return template((x) => {
const handleChange = ({target}) => {
temperaturesState[fromScale] = target.value
const toScales = Object.keys(converters[fromScale])
for (const toScale of toScales) {
temperaturesState[toScale] = convert(fromScale, toScale, target.value)
}
}
x.div(
x.input({
onKeyUp: handleChange,
value: () => temperaturesState[fromScale],
}),
x.label(scaleNames[fromScale])
)
})
}
css
#temperature-converter {
padding: 0.4rem;
width: fit-content;
border-radius: 0.4rem;
border: 0.1rem solid currentColor;
& div {
display: table;
& label {
display: table-cell;
padding: 0.3rem;
width: 5rem;
}
& input {
display: table-cell;
margin: 0.3rem;
padding: 0 0.3rem;
width: 5rem;
border: 0.1rem solid deepskyblue;
border-radius: 0.4rem;
}
}
}
html
<div id="temperature-converter"></div>