stocks / static /js /view-toggle.js
Arrechenash's picture
Initial Commit
3aed849
Raw
History Blame Contribute Delete
3.1 kB
/**
* ViewToggle - Unified component for view mode selection
*
* Usage:
* const toggle = new ViewToggle('#container', {
* options: [
* { value: 'list', label: 'List' },
* { value: 'charts', label: 'Charts' }
* ],
* default: 'charts',
* storageKey: 'gapup_view_mode',
* onChange: (mode) => { }
* })
*
* Or use the helper for common configs:
* ViewToggle.createListChart('#container', 'gapup_view_mode')
* ViewToggle.createGridView('#container', 'scanner_view')
*/
class ViewToggle {
constructor(containerOrSelector, options = {}) {
this.container =
typeof containerOrSelector === "string"
? document.querySelector(containerOrSelector)
: containerOrSelector;
this.options = {
options: options.options || [
{ value: "list", label: "List" },
{ value: "charts", label: "Charts" },
],
default: options.default || options.options?.[0]?.value || "list",
storageKey: options.storageKey || null,
onChange: options.onChange || (() => {}),
align: options.align || "start", // 'start', 'center', 'end'
};
this.currentMode = this._loadState();
this._render();
}
_loadState() {
if (this.options.storageKey) {
return (
localStorage.getItem(this.options.storageKey) || this.options.default
);
}
return this.options.default;
}
_saveState(mode) {
if (this.options.storageKey) {
localStorage.setItem(this.options.storageKey, mode);
}
}
_render() {
const buttons = this.options.options
.map((opt) => {
const isActive = opt.value === this.currentMode;
return `<button class="view-btn ${isActive ? "active" : ""}"
data-mode="${opt.value}">${opt.label}</button>`;
})
.join("");
this.container.innerHTML = `
<div class="view-toggle" data-align="${this.options.align}">
${buttons}
</div>
`;
// Add event listeners
this.container.querySelectorAll(".view-btn").forEach((btn) => {
btn.addEventListener("click", () => {
this._handleClick(btn.dataset.mode);
});
});
}
_handleClick(mode) {
if (mode === this.currentMode) return;
this.currentMode = mode;
this._saveState(mode);
this._updateButtons();
this.options.onChange(mode);
}
_updateButtons() {
this.container.querySelectorAll(".view-btn").forEach((btn) => {
btn.classList.toggle("active", btn.dataset.mode === this.currentMode);
});
}
/** Get current view mode */
getValue() {
return this.currentMode;
}
/** Set current mode programmatically */
setValue(mode) {
const validMode = this.options.options.some((o) => o.value === mode);
if (validMode) {
this._handleClick(mode);
}
}
/** Destroy and clean up */
destroy() {
this.container.innerHTML = "";
}
/**
* Factory: List vs Charts toggle (for watchlist, gainers)
*/
static createListChart(containerSelector, storageKey, onChange = () => {}) {
return new ViewToggle(containerSelector, {
options: [
{ value: "list", label: "List" },
{ value: "charts", label: "Charts" },
],
default: "charts",
storageKey: storageKey,
onChange: onChange,
});
}
}