mirror of
https://github.com/olehomelchenko/astrolabe-nvc.git
synced 2025-12-21 21:22:23 +00:00
refactor: simplify modal handling and improve settings management
This commit is contained in:
181
src/js/app.js
181
src/js/app.js
@@ -146,34 +146,22 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (helpLink) {
|
if (helpLink) {
|
||||||
helpLink.addEventListener('click', function () {
|
helpLink.addEventListener('click', () => ModalManager.open('help-modal'));
|
||||||
openHelpModal();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const donateLink = document.getElementById('donate-link');
|
const donateLink = document.getElementById('donate-link');
|
||||||
if (donateLink) {
|
if (donateLink) {
|
||||||
donateLink.addEventListener('click', function () {
|
donateLink.addEventListener('click', () => ModalManager.open('donate-modal'));
|
||||||
openDonateModal();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Settings Modal
|
// Settings Modal
|
||||||
const settingsLink = document.getElementById('settings-link');
|
const settingsLink = document.getElementById('settings-link');
|
||||||
const settingsModal = document.getElementById('settings-modal');
|
|
||||||
const settingsModalClose = document.getElementById('settings-modal-close');
|
|
||||||
const settingsApplyBtn = document.getElementById('settings-apply-btn');
|
const settingsApplyBtn = document.getElementById('settings-apply-btn');
|
||||||
const settingsResetBtn = document.getElementById('settings-reset-btn');
|
const settingsResetBtn = document.getElementById('settings-reset-btn');
|
||||||
const settingsCancelBtn = document.getElementById('settings-cancel-btn');
|
const settingsCancelBtn = document.getElementById('settings-cancel-btn');
|
||||||
|
|
||||||
if (settingsLink) {
|
if (settingsLink) {
|
||||||
settingsLink.addEventListener('click', function () {
|
settingsLink.addEventListener('click', openSettingsModal);
|
||||||
openSettingsModal();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settingsModalClose) {
|
|
||||||
settingsModalClose.addEventListener('click', closeSettingsModal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsCancelBtn) {
|
if (settingsCancelBtn) {
|
||||||
@@ -194,14 +182,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close on overlay click
|
|
||||||
if (settingsModal) {
|
|
||||||
settingsModal.addEventListener('click', function (e) {
|
|
||||||
if (e.target === settingsModal) {
|
|
||||||
closeSettingsModal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings UI interactions
|
// Settings UI interactions
|
||||||
const fontSizeSlider = document.getElementById('setting-font-size');
|
const fontSizeSlider = document.getElementById('setting-font-size');
|
||||||
@@ -235,8 +215,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
// Dataset Manager
|
// Dataset Manager
|
||||||
const datasetsLink = document.getElementById('datasets-link');
|
const datasetsLink = document.getElementById('datasets-link');
|
||||||
const toggleDatasetsBtn = document.getElementById('toggle-datasets');
|
const toggleDatasetsBtn = document.getElementById('toggle-datasets');
|
||||||
const datasetModal = document.getElementById('dataset-modal');
|
|
||||||
const datasetModalClose = document.getElementById('dataset-modal-close');
|
|
||||||
const newDatasetBtn = document.getElementById('new-dataset-btn');
|
const newDatasetBtn = document.getElementById('new-dataset-btn');
|
||||||
const cancelDatasetBtn = document.getElementById('cancel-dataset-btn');
|
const cancelDatasetBtn = document.getElementById('cancel-dataset-btn');
|
||||||
const saveDatasetBtn = document.getElementById('save-dataset-btn');
|
const saveDatasetBtn = document.getElementById('save-dataset-btn');
|
||||||
@@ -251,20 +229,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
toggleDatasetsBtn.addEventListener('click', openDatasetManager);
|
toggleDatasetsBtn.addEventListener('click', openDatasetManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close dataset manager
|
|
||||||
if (datasetModalClose) {
|
|
||||||
datasetModalClose.addEventListener('click', closeDatasetManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close on overlay click
|
|
||||||
if (datasetModal) {
|
|
||||||
datasetModal.addEventListener('click', function (e) {
|
|
||||||
if (e.target === datasetModal) {
|
|
||||||
closeDatasetManager();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// New dataset button
|
// New dataset button
|
||||||
if (newDatasetBtn) {
|
if (newDatasetBtn) {
|
||||||
newDatasetBtn.addEventListener('click', showNewDatasetForm);
|
newDatasetBtn.addEventListener('click', showNewDatasetForm);
|
||||||
@@ -339,39 +303,21 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help Modal
|
// Global modal event delegation - handles close buttons and overlay clicks
|
||||||
const helpModal = document.getElementById('help-modal');
|
document.addEventListener('click', function(e) {
|
||||||
const helpModalClose = document.getElementById('help-modal-close');
|
// Handle modal close buttons (×)
|
||||||
|
if (e.target.id && e.target.id.endsWith('-modal-close')) {
|
||||||
|
const modalId = e.target.id.replace('-close', '');
|
||||||
|
ModalManager.close(modalId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (helpModalClose) {
|
// Handle overlay clicks (clicking outside modal content)
|
||||||
helpModalClose.addEventListener('click', closeHelpModal);
|
if (e.target.classList.contains('modal')) {
|
||||||
}
|
ModalManager.close(e.target.id);
|
||||||
|
return;
|
||||||
// Close on overlay click
|
}
|
||||||
if (helpModal) {
|
});
|
||||||
helpModal.addEventListener('click', function (e) {
|
|
||||||
if (e.target === helpModal) {
|
|
||||||
closeHelpModal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Donate Modal
|
|
||||||
const donateModal = document.getElementById('donate-modal');
|
|
||||||
const donateModalClose = document.getElementById('donate-modal-close');
|
|
||||||
|
|
||||||
if (donateModalClose) {
|
|
||||||
donateModalClose.addEventListener('click', closeDonateModal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close on overlay click
|
|
||||||
if (donateModal) {
|
|
||||||
donateModal.addEventListener('click', function (e) {
|
|
||||||
if (e.target === donateModal) {
|
|
||||||
closeDonateModal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// View mode toggle buttons
|
// View mode toggle buttons
|
||||||
document.getElementById('view-draft').addEventListener('click', () => {
|
document.getElementById('view-draft').addEventListener('click', () => {
|
||||||
@@ -406,14 +352,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract modal buttons
|
// Extract modal buttons
|
||||||
const extractModalClose = document.getElementById('extract-modal-close');
|
|
||||||
const extractCancelBtn = document.getElementById('extract-cancel-btn');
|
const extractCancelBtn = document.getElementById('extract-cancel-btn');
|
||||||
const extractCreateBtn = document.getElementById('extract-create-btn');
|
const extractCreateBtn = document.getElementById('extract-create-btn');
|
||||||
const extractModal = document.getElementById('extract-modal');
|
|
||||||
|
|
||||||
if (extractModalClose) {
|
|
||||||
extractModalClose.addEventListener('click', hideExtractModal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extractCancelBtn) {
|
if (extractCancelBtn) {
|
||||||
extractCancelBtn.addEventListener('click', hideExtractModal);
|
extractCancelBtn.addEventListener('click', hideExtractModal);
|
||||||
@@ -422,15 +362,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
if (extractCreateBtn) {
|
if (extractCreateBtn) {
|
||||||
extractCreateBtn.addEventListener('click', extractToDataset);
|
extractCreateBtn.addEventListener('click', extractToDataset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close modal on overlay click
|
|
||||||
if (extractModal) {
|
|
||||||
extractModal.addEventListener('click', function (e) {
|
|
||||||
if (e.target === extractModal) {
|
|
||||||
hideExtractModal();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle URL hash changes (browser back/forward)
|
// Handle URL hash changes (browser back/forward)
|
||||||
@@ -495,8 +426,7 @@ const KeyboardActions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
toggleSettings: function() {
|
toggleSettings: function() {
|
||||||
const modal = document.getElementById('settings-modal');
|
if (ModalManager.isOpen('settings-modal')) {
|
||||||
if (modal && modal.style.display === 'flex') {
|
|
||||||
closeSettingsModal();
|
closeSettingsModal();
|
||||||
} else {
|
} else {
|
||||||
openSettingsModal();
|
openSettingsModal();
|
||||||
@@ -504,30 +434,19 @@ const KeyboardActions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
closeAnyModal: function() {
|
closeAnyModal: function() {
|
||||||
const helpModal = document.getElementById('help-modal');
|
// Try ModalManager first for standard modals
|
||||||
const datasetModal = document.getElementById('dataset-modal');
|
if (ModalManager.closeAny()) {
|
||||||
const extractModal = document.getElementById('extract-modal');
|
|
||||||
const donateModal = document.getElementById('donate-modal');
|
|
||||||
const settingsModal = document.getElementById('settings-modal');
|
|
||||||
|
|
||||||
if (helpModal && helpModal.style.display === 'flex') {
|
|
||||||
closeHelpModal();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (datasetModal && datasetModal.style.display === 'flex') {
|
// Handle special modals with custom close logic
|
||||||
closeDatasetManager();
|
if (ModalManager.isOpen('extract-modal')) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (extractModal && extractModal.style.display === 'flex') {
|
|
||||||
hideExtractModal();
|
hideExtractModal();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (donateModal && donateModal.style.display === 'flex') {
|
// Dataset manager has special close logic (URL state)
|
||||||
closeDonateModal();
|
const datasetModal = document.getElementById('dataset-modal');
|
||||||
return true;
|
if (datasetModal && datasetModal.style.display === 'flex') {
|
||||||
}
|
closeDatasetManager();
|
||||||
if (settingsModal && settingsModal.style.display === 'flex') {
|
|
||||||
closeSettingsModal();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -594,56 +513,14 @@ function registerMonacoKeyboardShortcuts() {
|
|||||||
KeyboardActions.publishDraft);
|
KeyboardActions.publishDraft);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help modal functions
|
// Settings modal functions (special handling for loading settings into UI)
|
||||||
function openHelpModal() {
|
|
||||||
const modal = document.getElementById('help-modal');
|
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'flex';
|
|
||||||
// Track event
|
|
||||||
Analytics.track('modal-help', 'Open Help modal');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeHelpModal() {
|
|
||||||
const modal = document.getElementById('help-modal');
|
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Donate modal functions
|
|
||||||
function openDonateModal() {
|
|
||||||
const modal = document.getElementById('donate-modal');
|
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'flex';
|
|
||||||
// Track event
|
|
||||||
Analytics.track('modal-donate', 'Open Donate modal');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDonateModal() {
|
|
||||||
const modal = document.getElementById('donate-modal');
|
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings modal functions
|
|
||||||
function openSettingsModal() {
|
function openSettingsModal() {
|
||||||
loadSettingsIntoUI();
|
loadSettingsIntoUI();
|
||||||
const modal = document.getElementById('settings-modal');
|
ModalManager.open('settings-modal');
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'flex';
|
|
||||||
// Track event
|
|
||||||
Analytics.track('modal-settings', 'Open Settings modal');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeSettingsModal() {
|
function closeSettingsModal() {
|
||||||
const modal = document.getElementById('settings-modal');
|
ModalManager.close('settings-modal');
|
||||||
if (modal) {
|
|
||||||
modal.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSettingsIntoUI() {
|
function loadSettingsIntoUI() {
|
||||||
|
|||||||
@@ -224,6 +224,52 @@ const Analytics = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Modal Manager - Generic modal control utility
|
||||||
|
const ModalManager = {
|
||||||
|
// Track which events to send to analytics when opening modals
|
||||||
|
trackingMap: {
|
||||||
|
'help-modal': ['modal-help', 'Open Help modal'],
|
||||||
|
'donate-modal': ['modal-donate', 'Open Donate modal'],
|
||||||
|
'settings-modal': ['modal-settings', 'Open Settings modal'],
|
||||||
|
'dataset-modal': ['modal-dataset', 'Open Dataset Manager']
|
||||||
|
},
|
||||||
|
|
||||||
|
open(modalId, shouldTrack = true) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
if (modal) {
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
if (shouldTrack && this.trackingMap[modalId]) {
|
||||||
|
const [event, title] = this.trackingMap[modalId];
|
||||||
|
Analytics.track(event, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
close(modalId) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
if (modal) {
|
||||||
|
modal.style.display = 'none';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isOpen(modalId) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
return modal && modal.style.display === 'flex';
|
||||||
|
},
|
||||||
|
|
||||||
|
// Close any open modal (for ESC key handler)
|
||||||
|
closeAny() {
|
||||||
|
const modalIds = ['help-modal', 'donate-modal', 'settings-modal', 'dataset-modal', 'extract-modal'];
|
||||||
|
for (const modalId of modalIds) {
|
||||||
|
if (this.isOpen(modalId)) {
|
||||||
|
this.close(modalId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Shared utility: Format bytes for display
|
// Shared utility: Format bytes for display
|
||||||
function formatBytes(bytes) {
|
function formatBytes(bytes) {
|
||||||
if (bytes === null || bytes === undefined) return 'N/A';
|
if (bytes === null || bytes === undefined) return 'N/A';
|
||||||
|
|||||||
@@ -87,42 +87,24 @@ function getSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get a specific setting by path (e.g., 'editor.fontSize')
|
// Get a specific setting by path (e.g., 'editor.fontSize')
|
||||||
|
// Simplified: assumes 2-level structure (section.key)
|
||||||
function getSetting(path) {
|
function getSetting(path) {
|
||||||
const settings = getSettings();
|
const settings = getSettings();
|
||||||
const parts = path.split('.');
|
const [section, key] = path.split('.');
|
||||||
let value = settings;
|
return settings?.[section]?.[key];
|
||||||
|
|
||||||
for (const part of parts) {
|
|
||||||
if (value && typeof value === 'object' && part in value) {
|
|
||||||
value = value[part];
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a specific setting by path
|
// Update a specific setting by path
|
||||||
|
// Simplified: assumes 2-level structure (section.key)
|
||||||
function updateSetting(path, value) {
|
function updateSetting(path, value) {
|
||||||
const settings = getSettings();
|
const settings = getSettings();
|
||||||
const parts = path.split('.');
|
const [section, key] = path.split('.');
|
||||||
let target = settings;
|
|
||||||
|
|
||||||
// Navigate to the parent object
|
if (settings[section]) {
|
||||||
for (let i = 0; i < parts.length - 1; i++) {
|
settings[section][key] = value;
|
||||||
const part = parts[i];
|
return saveSettings();
|
||||||
if (!target[part] || typeof target[part] !== 'object') {
|
|
||||||
target[part] = {};
|
|
||||||
}
|
|
||||||
target = target[part];
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
// Set the value
|
|
||||||
const lastPart = parts[parts.length - 1];
|
|
||||||
target[lastPart] = value;
|
|
||||||
|
|
||||||
return saveSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update multiple settings at once
|
// Update multiple settings at once
|
||||||
@@ -130,19 +112,10 @@ function updateSettings(updates) {
|
|||||||
const settings = getSettings();
|
const settings = getSettings();
|
||||||
|
|
||||||
for (const path in updates) {
|
for (const path in updates) {
|
||||||
const parts = path.split('.');
|
const [section, key] = path.split('.');
|
||||||
let target = settings;
|
if (settings[section]) {
|
||||||
|
settings[section][key] = updates[path];
|
||||||
for (let i = 0; i < parts.length - 1; i++) {
|
|
||||||
const part = parts[i];
|
|
||||||
if (!target[part] || typeof target[part] !== 'object') {
|
|
||||||
target[part] = {};
|
|
||||||
}
|
|
||||||
target = target[part];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastPart = parts[parts.length - 1];
|
|
||||||
target[lastPart] = updates[path];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return saveSettings();
|
return saveSettings();
|
||||||
@@ -154,23 +127,6 @@ function resetSettings() {
|
|||||||
return saveSettings();
|
return saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export settings as JSON
|
|
||||||
function exportSettings() {
|
|
||||||
return JSON.stringify(getSettings(), null, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import settings from JSON string
|
|
||||||
function importSettings(jsonString) {
|
|
||||||
try {
|
|
||||||
const imported = JSON.parse(jsonString);
|
|
||||||
userSettings = mergeWithDefaults(imported);
|
|
||||||
return saveSettings();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error importing settings:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format date according to user settings
|
// Format date according to user settings
|
||||||
function formatDate(isoString, useFullFormat = false) {
|
function formatDate(isoString, useFullFormat = false) {
|
||||||
const date = new Date(isoString);
|
const date = new Date(isoString);
|
||||||
@@ -253,48 +209,16 @@ function formatCustomDate(date, format) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate setting value
|
// Validate setting value - simplified with inline validation rules
|
||||||
function validateSetting(path, value) {
|
function validateSetting(path, value) {
|
||||||
const errors = [];
|
const rules = {
|
||||||
|
'editor.fontSize': () => typeof value === 'number' && value >= 10 && value <= 18 ? [] : ['Font size must be between 10 and 18'],
|
||||||
|
'editor.theme': () => ['vs-light', 'vs-dark', 'hc-black'].includes(value) ? [] : ['Invalid editor theme'],
|
||||||
|
'editor.tabSize': () => typeof value === 'number' && value >= 2 && value <= 8 ? [] : ['Tab size must be between 2 and 8'],
|
||||||
|
'performance.renderDebounce': () => typeof value === 'number' && value >= 300 && value <= 3000 ? [] : ['Render debounce must be between 300-3000ms'],
|
||||||
|
'formatting.dateFormat': () => ['smart', 'locale', 'iso', 'custom'].includes(value) ? [] : ['Invalid date format'],
|
||||||
|
'ui.theme': () => ['light', 'experimental'].includes(value) ? [] : ['Invalid UI theme']
|
||||||
|
};
|
||||||
|
|
||||||
if (path === 'editor.fontSize') {
|
return rules[path] ? rules[path]() : [];
|
||||||
if (typeof value !== 'number' || value < 10 || value > 18) {
|
|
||||||
errors.push('Font size must be between 10 and 18');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === 'editor.theme') {
|
|
||||||
const validThemes = ['vs-light', 'vs-dark', 'hc-black'];
|
|
||||||
if (!validThemes.includes(value)) {
|
|
||||||
errors.push('Invalid theme value');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === 'editor.tabSize') {
|
|
||||||
if (typeof value !== 'number' || value < 2 || value > 8) {
|
|
||||||
errors.push('Tab size must be between 2 and 8');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === 'performance.renderDebounce') {
|
|
||||||
if (typeof value !== 'number' || value < 300 || value > 3000) {
|
|
||||||
errors.push('Render debounce must be between 300 and 3000ms');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === 'formatting.dateFormat') {
|
|
||||||
const validFormats = ['smart', 'locale', 'iso', 'custom'];
|
|
||||||
if (!validFormats.includes(value)) {
|
|
||||||
errors.push('Invalid date format value');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === 'ui.theme') {
|
|
||||||
const validThemes = ['light', 'experimental'];
|
|
||||||
if (!validThemes.includes(value)) {
|
|
||||||
errors.push('Invalid theme value');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user