diff --git a/public/app.js b/public/app.js
index 52f9794..9ae96f4 100644
--- a/public/app.js
+++ b/public/app.js
@@ -1,116 +1,19 @@
// ========================================
-// SteelBase v6.5 - PROFESSIONAL EDITION
+// SteelBase v7.5 - PROFESSIONAL EDITION
// Plataforma Técnica Completa com Base de Materiais
// ========================================
-// In-memory data storage WITH localStorage for preferences
+// Import state from modules (userPreferences only - appState is still global for legacy)
+import { userPreferences, loadPreferences, savePreferences, adminConfig } from './js/core/state.js';
+
+// Make available globally for legacy code
+window.userPreferences = userPreferences;
+window.loadPreferences = loadPreferences;
+window.savePreferences = savePreferences;
+window.adminConfig = adminConfig;
+
+// In-memory data storage (legacy - still global for compatibility)
const appState = {
- history: [],
- favorites: [],
- budgetItems: [],
- currentSection: 'cev',
- currentTheme: 'dark', // 'dark' or 'light'
- expertMode: false,
- currentSidebarTab: 0
-};
-
-// User preferences (saved to localStorage)
-let userPreferences = {
- theme: 'dark',
- colorScheme: 'default', // default, blue, green, purple, orange
- fontSize: 'medium', // small, medium, large, xlarge
- fontFamily: 'default' // default, modern, classic, mono
-};
-
-// Load preferences from localStorage
-function loadPreferences() {
- try {
- const saved = localStorage.getItem('acoCalcPreferences');
- if (saved) {
- userPreferences = { ...userPreferences, ...JSON.parse(saved) };
- }
- } catch (e) {
- console.warn('Não foi possível carregar preferências:', e);
- }
-}
-
-// Save preferences to localStorage
-function savePreferences() {
- try {
- localStorage.setItem('acoCalcPreferences', JSON.stringify(userPreferences));
- } catch (e) {
- console.warn('Não foi possível salvar preferências:', e);
- }
-}
-
-// Admin configuration (in-memory)
-const adminConfig = {
- appName: 'SteelBase',
- appSubtitle: 'Plataforma Técnica com Base de Dados de Materiais Brasileiros',
- footerText: '© 2025 SteelBase v6.5 PROFESSIONAL EDITION - Plataforma Técnica com Base de Dados de Materiais Brasileiros',
- themeDefault: 'escuro',
- modeDefault: 'simples',
- toolsVisibility: {
- // Aços Estruturais
- 'cev': true,
- 'seletor': true,
- 'equivalencias': false,
- 'comparativo': false,
- 'assistente-inteligente': true,
- // Consumíveis de Soldagem
- 'eletrodos': false,
- 'arames': false,
- 'fluxos': false,
- 'gases': false,
- // Fixadores
- 'parafusos-catalogo': false,
- 'porcas': false,
- 'arruelas': false,
- 'chumbadores': false,
- // Tintas e Revestimentos
- 'tintas-catalogo': false,
- 'sistemas-pintura': false,
- 'abrasivos': false,
- 'granalha': false,
- // Elementos Complementares
- 'telhas': false,
- 'paineis': false,
- 'steel-deck': false,
- 'perfis-formados': false,
- // Catálogo de Perfis
- 'cantoneiras': true,
- 'barras-redondas': true,
- 'tubos-circulares': true,
- 'perfis-i': true,
- 'perfis-w': true,
- 'tubos-rhs': true,
- 'chapas': true,
- 'perfis-hp': true,
- 'barras-roscadas': true,
- 'barras-chatas': true,
- // Conexões
- 'parafusos': true,
- 'layout': true,
- 'parafuso-vs-solda': false,
- // Soldagem
- 'preaquecimento': true,
- 'dureza': true,
- 'charpy': true,
- 'certificado': false,
- 'ultrassom': false,
- // Pintura
- 'area-pintura': true,
- 'consumo-tinta': true,
- 'galvanizacao': false,
- 'custo-pintura': true,
- 'secagem': false,
- 'inspecao-pintura': false,
- // Orçamento
- 'orcamento': true,
- 'peso-rigging': false,
- 'referencia': false
- }
-};
// ========================================
// CSV MAPPING AND LOADING FUNCTIONS v6.6
@@ -431,108 +334,6 @@ function showSection(sectionId) {
}, 500);
}
- // CÓDIGO ANTIGO REMOVIDO - mantido apenas para referência
- if (false && sectionId === 'cantoneiras') {
- console.log('🔧 Seção cantoneiras detectada - iniciando carregamento forçado');
-
- // Tentar múltiplas vezes até conseguir
- let tentativas = 0;
- const maxTentativas = 10;
-
- const tentarCarregar = async () => {
- tentativas++;
- console.log(`🔄 Tentativa ${tentativas}/${maxTentativas} de carregar cantoneiras`);
-
- const tbody = document.getElementById('cantoneiras-tbody');
-
- if (tbody) {
- console.log('✅ Elemento tbody encontrado! Carregando dados...');
-
- try {
- // Carregar CSV diretamente
- const response = await fetch('BD/perfis/cantoneiras_brasil_completo.csv');
- if (!response.ok) {
- throw new Error(`HTTP ${response.status}`);
- }
-
- const csvText = await response.text();
- const linhas = csvText.trim().split('\n');
-
- console.log(`📊 CSV carregado: ${linhas.length} linhas`);
-
- const dados = [];
- for (let i = 1; i < linhas.length; i++) {
- const linha = linhas[i].trim();
- if (!linha) continue;
-
- const colunas = linha.split(',');
- if (colunas.length >= 9) {
- dados.push({
- id: colunas[0].trim(),
- nome: colunas[1].trim(),
- lado_mm: parseFloat(colunas[2]),
- espessura_mm: parseFloat(colunas[3]),
- peso_kg_m: parseFloat(colunas[4]),
- area_cm2: parseFloat(colunas[5]),
- momento_inercia_cm4: parseFloat(colunas[6]),
- raio_giracao_cm: parseFloat(colunas[7]),
- tipo: colunas[8].trim()
- });
- }
- }
-
- console.log(`✅ Processados: ${dados.length} cantoneiras`);
-
- // Exibir na tabela
- tbody.innerHTML = dados.map(item => `
-
- | ${item.nome} |
- ${item.lado_mm} |
- ${item.espessura_mm} |
- ${item.peso_kg_m.toFixed(2)} |
- ${item.area_cm2.toFixed(2)} |
- ${item.momento_inercia_cm4.toFixed(2)} |
- ${item.raio_giracao_cm.toFixed(2)} |
- ${item.tipo} |
- |
-
- `).join('');
-
- console.log('🎉 Tabela preenchida com sucesso!');
-
- // Atualizar contador
- const totalEl = document.getElementById('cant-total');
- if (totalEl) {
- totalEl.textContent = dados.length;
- }
-
- } catch (error) {
- console.error('❌ Erro ao carregar CSV:', error);
- tbody.innerHTML = `
-
-
- ❌ Erro ao carregar dados: ${error.message}
-
-
- |
-
- `;
- }
- } else {
- console.warn(`⚠️ Elemento tbody não encontrado (tentativa ${tentativas})`);
-
- if (tentativas < maxTentativas) {
- setTimeout(tentarCarregar, 300);
- } else {
- console.error('❌ Falha após todas as tentativas');
- }
- }
- };
-
- // Iniciar tentativas após um pequeno delay
- setTimeout(tentarCarregar, 200);
- }
-
// Add help button after content loads
setTimeout(() => {
if (sectionId === 'preaquecimento') {
diff --git a/public/js/core/state.js b/public/js/core/state.js
index d6aba2d..5abb320 100644
--- a/public/js/core/state.js
+++ b/public/js/core/state.js
@@ -15,13 +15,34 @@ export const appState = {
};
// User preferences (persisted to localStorage)
-export const userPreferences = {
+export let userPreferences = {
theme: 'dark',
- colorScheme: 'default', // default, blue, green, purple, orange
- fontSize: 'medium', // small, medium, large, xlarge
- fontFamily: 'default' // default, modern, classic, mono
+ colorScheme: 'default',
+ fontSize: 'medium',
+ fontFamily: 'default'
};
+// Load preferences from localStorage
+export function loadPreferences() {
+ try {
+ const saved = localStorage.getItem('acoCalcPreferences');
+ if (saved) {
+ userPreferences = { ...userPreferences, ...JSON.parse(saved) };
+ }
+ } catch (e) {
+ console.warn('Não foi possível carregar preferências:', e);
+ }
+}
+
+// Save preferences to localStorage
+export function savePreferences() {
+ try {
+ localStorage.setItem('acoCalcPreferences', JSON.stringify(userPreferences));
+ } catch (e) {
+ console.warn('Não foi possível salvar preferências:', e);
+ }
+}
+
// Admin configuration
export const adminConfig = {
appName: 'SteelBase',
@@ -89,3 +110,26 @@ export function updatePreference(key, value) {
export function getPreference(key) {
return userPreferences[key];
}
+
+/**
+ * Check if localStorage is available and has space
+ * @returns {object} Storage status
+ */
+export function checkStorage() {
+ try {
+ const testKey = '__storage_test__';
+ localStorage.setItem(testKey, testKey);
+ localStorage.removeItem(testKey);
+
+ let totalSize = 0;
+ for (let key in localStorage) {
+ if (localStorage.hasOwnProperty(key)) {
+ totalSize += localStorage[key].length * 2;
+ }
+ }
+
+ return { available: true, usedBytes: totalSize };
+ } catch (error) {
+ return { available: false, error: error.message };
+ }
+}
diff --git a/public/js/core/toast-manager.js b/public/js/core/toast-manager.js
deleted file mode 100644
index 517ab79..0000000
--- a/public/js/core/toast-manager.js
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * ToastManager - Sistema de Notificações Visuais
- * Gerencia notificações toast não-intrusivas para o usuário
- */
-class ToastManager {
- constructor() {
- this.container = null;
- this.toasts = new Map();
- this.config = {
- position: 'top-right',
- duration: 5000,
- maxToasts: 5,
- animationDuration: 300
- };
- this.init();
- }
-
- init() {
- this.createContainer();
- console.log('🍞 ToastManager inicializado');
- }
-
- createContainer() {
- // Remover container existente se houver
- const existingContainer = document.querySelector('.toast-container');
- if (existingContainer) {
- existingContainer.remove();
- }
-
- // Criar novo container
- this.container = document.createElement('div');
- this.container.className = `toast-container toast-${this.config.position}`;
- this.container.style.cssText = `
- position: fixed;
- z-index: 10000;
- pointer-events: none;
- `;
-
- // Definir posição baseada na configuração
- this.setContainerPosition();
-
- document.body.appendChild(this.container);
- }
-
- setContainerPosition() {
- if (!this.container) return;
-
- const positions = {
- 'top-right': { top: '20px', right: '20px', bottom: 'auto', left: 'auto' },
- 'top-left': { top: '20px', left: '20px', bottom: 'auto', right: 'auto' },
- 'top-center': { top: '20px', left: '50%', transform: 'translateX(-50%)', bottom: 'auto', right: 'auto' },
- 'bottom-right': { bottom: '20px', right: '20px', top: 'auto', left: 'auto' },
- 'bottom-left': { bottom: '20px', left: '20px', top: 'auto', right: 'auto' },
- 'bottom-center': { bottom: '20px', left: '50%', transform: 'translateX(-50%)', top: 'auto', right: 'auto' }
- };
-
- const pos = positions[this.config.position] || positions['top-right'];
- Object.assign(this.container.style, pos);
- }
-
- show(message, type = 'info', duration = null, options = {}) {
- const toast = this.createToast(message, type, options);
- const toastId = toast.dataset.toastId;
-
- // Adicionar ao container
- this.container.appendChild(toast);
-
- // Armazenar referência
- this.toasts.set(toastId, toast);
-
- // Limitar número de toasts
- this.limitToasts();
-
- // Animar entrada
- requestAnimationFrame(() => {
- toast.classList.add('show');
- });
-
- // Configurar tempo de remoção
- const autoHideDuration = duration !== null ? duration : this.config.duration;
- if (autoHideDuration > 0) {
- setTimeout(() => {
- this.hide(toastId);
- }, autoHideDuration);
- }
-
- return toastId;
- }
-
- createToast(message, type, options) {
- const toast = document.createElement('div');
- const toastId = 'toast_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
-
- toast.dataset.toastId = toastId;
- toast.className = `toast toast-${type}`;
- toast.style.cssText = `
- background: var(--toast-bg, #333);
- color: var(--toast-color, #fff);
- padding: 16px 20px;
- margin-bottom: 10px;
- border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.15);
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- font-size: 14px;
- line-height: 1.4;
- max-width: 400px;
- min-width: 300px;
- opacity: 0;
- transform: translateX(100%);
- transition: all ${this.config.animationDuration}ms ease;
- pointer-events: auto;
- position: relative;
- overflow: hidden;
- `;
-
- // Definir cores baseadas no tipo
- const colors = {
- success: { bg: '#22c55e', color: '#fff' },
- error: { bg: '#ef4444', color: '#fff' },
- warning: { bg: '#f59e0b', color: '#fff' },
- info: { bg: '#3b82f6', color: '#fff' }
- };
-
- const colorConfig = colors[type] || colors.info;
- toast.style.setProperty('--toast-bg', colorConfig.bg);
- toast.style.setProperty('--toast-color', colorConfig.color);
-
- // Adicionar ícone baseado no tipo
- const icons = {
- success: '✅',
- error: '❌',
- warning: '⚠️',
- info: 'ℹ️'
- };
-
- const icon = options.icon || icons[type] || icons.info;
-
- toast.innerHTML = `
-
-
${icon}
-
${message}
-
-
- `;
-
- return toast;
- }
-
- limitToasts() {
- if (this.toasts.size <= this.config.maxToasts) return;
-
- const toastsArray = Array.from(this.toasts.entries());
- const toRemove = toastsArray.slice(0, toastsArray.length - this.config.maxToasts);
-
- toRemove.forEach(([toastId]) => {
- this.hide(toastId);
- });
- }
-
- hide(toastId) {
- const toast = this.toasts.get(toastId);
- if (!toast) return;
-
- toast.classList.remove('show');
-
- setTimeout(() => {
- if (toast.parentNode) {
- toast.parentNode.removeChild(toast);
- }
- this.toasts.delete(toastId);
- }, this.config.animationDuration);
- }
-
- hideAll() {
- this.toasts.forEach((toast, toastId) => {
- this.hide(toastId);
- });
- }
-
- // Métodos de conveniência
- success(message, duration, options) {
- return this.show(message, 'success', duration, options);
- }
-
- error(message, duration, options) {
- return this.show(message, 'error', duration, options);
- }
-
- warning(message, duration, options) {
- return this.show(message, 'warning', duration, options);
- }
-
- info(message, duration, options) {
- return this.show(message, 'info', duration, options);
- }
-
- // Configurar posição
- setPosition(position) {
- if (['top-right', 'top-left', 'top-center', 'bottom-right', 'bottom-left', 'bottom-center'].includes(position)) {
- this.config.position = position;
- this.createContainer();
- }
- }
-
- // Obter estatísticas
- getStats() {
- return {
- activeToasts: this.toasts.size,
- maxToasts: this.config.maxToasts,
- position: this.config.position,
- duration: this.config.duration
- };
- }
-}
-
-// Tornar disponível globalmente
-window.ToastManager = ToastManager;
-window.toastManager = new ToastManager();
\ No newline at end of file