Spaces:
Running
Running
| /** | |
| * 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, | |
| }); | |
| } | |
| } | |