mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
A screenshot review of the Spanish UI found: - Text left in English. Catalog entries copied from English (Bloom, Cyber, Pin, NEWS, SITE, ON/OFF, RANGE, PITCH, HGT…) and the radio music genres, which never went through t(). The genres are translated in es and ru now. - Wording: gender agreement, calques of the English, hints that name buttons that do not exist, and one concept worded two ways. - Layout: the DESACTIVADO pill squeezed layer names until words broke mid-word; the scene and camera selects showed one word; a collapsed rail title pushed its button out of the card; the image slot line and a comparison readout were cut or split. The layout fixes are scoped to languages other than English, so English stays pixel-identical. Visual-style slider values now use the locale's decimal separator (0,85). npm run i18n now reports a translation that is identical to the English, unless src/i18n/same-as-english.json lists it for that language (codes, product names, words spelled the same). Co-Authored-By: Claude Opus 5.5 <[email protected]>
79 lines
2.7 KiB
JavaScript
79 lines
2.7 KiB
JavaScript
import { formatNumber, t } from '../i18n/index.js';
|
|
|
|
/** A slider value in the UI language: 0.85 in English, 0,85 in Spanish. */
|
|
const formatParam = (value, digits) =>
|
|
formatNumber(value, {
|
|
minimumFractionDigits: digits,
|
|
maximumFractionDigits: digits,
|
|
useGrouping: false,
|
|
});
|
|
|
|
/**
|
|
* Own generated parameter rows and their input listeners.
|
|
* The caller supplies uniform metadata/value access and rendering/persistence
|
|
* callbacks. Replacing or destroying rows revokes all old input handlers.
|
|
* @param {object} options
|
|
* @param {HTMLElement} options.container Container owned by this component.
|
|
* @param {Document} [options.documentRef] Document used to construct rows.
|
|
* @returns {{render: Function, clear: Function, destroy: Function}}
|
|
*/
|
|
export function createStyleParameters({
|
|
container,
|
|
documentRef = container.ownerDocument,
|
|
}) {
|
|
let listeners = [];
|
|
let destroyed = false;
|
|
const clear = () => {
|
|
if (destroyed) return;
|
|
for (const [slider, listener] of listeners)
|
|
slider.removeEventListener('input', listener);
|
|
listeners = [];
|
|
container.replaceChildren();
|
|
};
|
|
return {
|
|
/** Render uniform metadata with readValue, writeValue and onChange callbacks. */
|
|
render({ uniforms, readValue, writeValue, onChange }) {
|
|
if (destroyed) return;
|
|
clear();
|
|
for (const [name, metadata] of Object.entries(uniforms)) {
|
|
const row = documentRef.createElement('div');
|
|
row.className = 'param-slider-row';
|
|
const label = documentRef.createElement('span');
|
|
label.className = 'param-label';
|
|
label.textContent = t(metadata.label);
|
|
const slider = documentRef.createElement('input');
|
|
slider.type = 'range';
|
|
slider.className = 'param-slider';
|
|
slider.setAttribute('aria-label', t(metadata.label));
|
|
slider.min = metadata.min;
|
|
slider.max = metadata.max;
|
|
slider.step = metadata.max <= 1 ? '0.01' : '0.1';
|
|
slider.value = readValue(name);
|
|
const digits = metadata.max <= 1 ? 2 : 1;
|
|
const valueDisplay = documentRef.createElement('span');
|
|
valueDisplay.className = 'param-value';
|
|
valueDisplay.textContent = formatParam(
|
|
parseFloat(slider.value),
|
|
digits,
|
|
);
|
|
const onInput = () => {
|
|
const value = parseFloat(slider.value);
|
|
writeValue(name, value);
|
|
valueDisplay.textContent = formatParam(value, digits);
|
|
onChange();
|
|
};
|
|
slider.addEventListener('input', onInput);
|
|
listeners.push([slider, onInput]);
|
|
row.append(label, slider, valueDisplay);
|
|
container.appendChild(row);
|
|
}
|
|
},
|
|
clear,
|
|
destroy() {
|
|
if (destroyed) return;
|
|
clear();
|
|
destroyed = true;
|
|
},
|
|
};
|
|
}
|