devdank's picture
## πŸ“£ Product Pitch: **Moot** β€” The Offline-First AI Media Intelligence Suite
ce53bc1 verified
// Global JavaScript for MootVision AI
// Initialize Feather Icons
document.addEventListener('DOMContentLoaded', function() {
if (typeof feather !== 'undefined') {
feather.replace();
}
});
// Theme management
class ThemeManager {
constructor() {
this.currentTheme = 'light';
this.init();
}
init() {
// Check for saved theme preference or default to light
const savedTheme = localStorage.getItem('mootvision-theme');
if (savedTheme) {
this.setTheme(savedTheme);
}
}
setTheme(theme) {
this.currentTheme = theme;
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('mootvision-theme', theme);
}
toggleTheme() {
const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
this.setTheme(newTheme);
}
}
// Initialize theme manager
const themeManager = new ThemeManager();
// API integration utilities
class API {
static baseURL = '/api';
static async get(endpoint) {
try {
const response = await fetch(`${this.baseURL}${endpoint}`);
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
}
static async post(endpoint, data) {
try {
const response = await fetch(`${this.baseURL}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
}
}
// Job progress tracking
class JobTracker {
constructor(jobId) {
this.jobId = jobId;
this.ws = null;
this.connect();
}
connect() {
this.ws = new WebSocket(`ws://localhost/api/ws/jobs/${this.jobId}`);
this.ws.onopen = () => {
console.log(`WebSocket connected for job ${this.jobId}`);
this.updateUI('connected');
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
this.handleMessage(data);
};
this.ws.onclose = () => {
console.log(`WebSocket disconnected for job ${this.jobId}`);
setTimeout(() => this.connect(), 5000); // Reconnect after 5 seconds
};
}
handleMessage(data) {
switch (data.type) {
case 'progress':
this.updateProgress(data.progress);
break;
case 'log':
this.appendLog(data.message);
break;
case 'completed':
this.jobCompleted(data.results);
break;
case 'error':
this.jobError(data.error);
break;
}
}
updateProgress(progress) {
const progressBar = document.getElementById(`progress-${this.jobId}`);
const progressText = document.getElementById(`progress-text-${this.jobId}`);
if (progressBar) {
progressBar.style.width = `${progress}%`;
}
if (progressText) {
progressText.textContent = `${progress}%`;
}
}
appendLog(message) {
const logContainer = document.getElementById(`logs-${this.jobId}`);
if (logContainer) {
const logEntry = document.createElement('div');
logEntry.className = 'text-sm text-gray-600';
logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
logContainer.appendChild(logEntry);
logContainer.scrollTop = logContainer.scrollHeight;
}
}
jobCompleted(results) {
this.updateUI('completed');
if (typeof window.jobCompletedCallback === 'function') {
window.jobCompletedCallback(results);
}
}
jobError(error) {
this.updateUI('error');
console.error('Job error:', error);
}
updateUI(status) {
// Update UI based on job status
const jobElement = document.getElementById(`job-${this.jobId}`);
if (jobElement) {
jobElement.setAttribute('data-status', status);
}
}
}
// Utility functions
const Utils = {
formatFileSize(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes === 0) return '0 Bytes';
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
},
formatDuration(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
},
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
};
// Export for use in other modules
window.API = API;
window.JobTracker = JobTracker;
window.Utils = Utils;
window.themeManager = themeManager;