'use strict'; 'require baseclass'; /** * SecuBox Development Status Widget * Real-time development progress tracker */ return baseclass.extend({ // Development milestones and progress milestones: { 'modules-core': { name: 'Core Modules', progress: 100, total: 13, completed: 13, icon: '๐Ÿ“ฆ', color: '#10b981', items: [ { name: 'Bandwidth Manager', status: 'completed' }, { name: 'Auth Guardian', status: 'completed' }, { name: 'Media Flow', status: 'completed' }, { name: 'VHost Manager', status: 'completed' }, { name: 'CrowdSec Dashboard', status: 'completed' }, { name: 'WireGuard Dashboard', status: 'completed' }, { name: 'Netdata Dashboard', status: 'completed' }, { name: 'Netifyd Dashboard', status: 'completed' }, { name: 'Client Guardian', status: 'completed' }, { name: 'Network Modes', status: 'completed' }, { name: 'Traffic Shaper', status: 'completed' }, { name: 'CDN Cache', status: 'completed' }, { name: 'SecuBox Hub', status: 'completed' } ] }, 'hardware-support': { name: 'Hardware Support', progress: 95, total: 4, completed: 3, icon: '๐Ÿ”ง', color: '#f59e0b', items: [ { name: 'ESPRESSObin Ultra', status: 'completed' }, { name: 'Sheeva64 (WiFi 6)', status: 'completed' }, { name: 'MOCHAbin (10GbE)', status: 'completed' }, { name: 'Performance Optimization', status: 'in-progress' } ] }, 'integration': { name: 'Integration & Testing', progress: 85, total: 6, completed: 5, icon: '๐Ÿงช', color: '#3b82f6', items: [ { name: 'LuCI Integration', status: 'completed' }, { name: 'RPCD Backends', status: 'completed' }, { name: 'ubus APIs', status: 'completed' }, { name: 'Multi-platform Build', status: 'completed' }, { name: 'Documentation', status: 'completed' }, { name: 'Beta Testing Program', status: 'in-progress' } ] }, 'campaign-prep': { name: 'Campaign Preparation', progress: 70, total: 5, completed: 3, icon: '๐Ÿš€', color: '#8b5cf6', items: [ { name: 'Website Multi-language', status: 'completed' }, { name: 'Demo Pages', status: 'completed' }, { name: 'Video Tutorials', status: 'in-progress' }, { name: 'Marketing Materials', status: 'in-progress' }, { name: 'Crowdfunding Setup', status: 'planned' } ] } }, // Overall project statistics stats: { modulesCount: 13, languagesSupported: 11, architectures: 4, linesOfCode: 15000, contributors: 3, commits: 450, openIssues: 12, closedIssues: 87 }, // Timeline data timeline: [ { phase: 'Phase 1', name: 'Core Development', period: 'Q4 2024 - Q1 2025', status: 'completed', progress: 100 }, { phase: 'Phase 2', name: 'Advanced Modules', period: 'Q1 - Q2 2025', status: 'completed', progress: 100 }, { phase: 'Phase 3', name: 'Hardware Integration', period: 'Q2 - Q4 2025', status: 'in-progress', progress: 95 }, { phase: 'Phase 4', name: 'Beta Testing', period: 'Q1 2026', status: 'in-progress', progress: 40 }, { phase: 'Phase 5', name: 'Crowdfunding Campaign', period: 'Q2 2026', status: 'planned', progress: 20 }, { phase: 'Phase 6', name: 'Production & Delivery', period: 'Q3 - Q4 2026', status: 'planned', progress: 0 } ], /** * Calculate overall progress */ getOverallProgress() { const milestones = Object.values(this.milestones); const totalProgress = milestones.reduce((sum, m) => sum + m.progress, 0); return Math.round(totalProgress / milestones.length); }, /** * Get current phase */ getCurrentPhase() { return this.timeline.find(p => p.status === 'in-progress') || this.timeline[0]; }, /** * Render the widget */ render(containerId) { const container = document.getElementById(containerId); if (!container) { console.error(`Container #${containerId} not found`); return; } const overallProgress = this.getOverallProgress(); const currentPhase = this.getCurrentPhase(); container.innerHTML = `
${this.renderHeader(overallProgress, currentPhase)} ${this.renderMilestones()} ${this.renderTimeline()} ${this.renderStats()}
`; this.addStyles(); this.animateProgressBars(); }, /** * Render header section */ renderHeader(progress, phase) { return `

๐Ÿš€ Development Status

Real-time project progress tracker

${progress}%
Current Phase
${phase.phase}: ${phase.name}
${phase.period}
`; }, /** * Render milestones section */ renderMilestones() { const milestonesHtml = Object.entries(this.milestones).map(([key, milestone]) => `
${milestone.icon} ${milestone.name}
${milestone.completed}/${milestone.total} ${milestone.progress}%
${milestone.items.map(item => `
${this.getStatusIcon(item.status)} ${item.name}
`).join('')}
`).join(''); return `

Development Milestones

${milestonesHtml}
`; }, /** * Render timeline section */ renderTimeline() { const timelineHtml = this.timeline.map((phase, index) => `
${index < this.timeline.length - 1 ? '
' : ''}
${phase.phase} ${phase.period}
${phase.name}
${phase.progress}%
`).join(''); return `

Project Timeline

${timelineHtml}
`; }, /** * Render statistics section */ renderStats() { return `

Project Statistics

${this.stats.modulesCount}
Modules
${this.stats.languagesSupported}
Languages
${this.stats.architectures}
Architectures
${(this.stats.linesOfCode / 1000).toFixed(1)}k
Lines of Code
${this.stats.contributors}
Contributors
${this.stats.commits}
Commits
${this.stats.openIssues}
Open Issues
${this.stats.closedIssues}
Closed Issues
`; }, /** * Get status icon */ getStatusIcon(status) { const icons = { 'completed': 'โœ…', 'in-progress': '๐Ÿ”„', 'planned': '๐Ÿ“‹' }; return icons[status] || 'โšช'; }, /** * Animate progress bars */ animateProgressBars() { setTimeout(() => { document.querySelectorAll('[data-progress]').forEach(element => { const progress = element.getAttribute('data-progress'); if (element.classList.contains('dsw-progress-bar-fill')) { element.style.width = `${progress}%`; } else if (element.classList.contains('dsw-timeline-progress-fill')) { element.style.width = `${progress}%`; } }); }, 100); }, /** * Add widget styles */ addStyles() { if (document.getElementById('dev-status-widget-styles')) return; const style = document.createElement('style'); style.id = 'dev-status-widget-styles'; style.textContent = ` .dev-status-widget { background: var(--sb-bg-card, #1a1a24); border: 1px solid var(--sb-border, #2a2a3a); border-radius: 20px; padding: 32px; color: var(--sb-text, #f1f5f9); } .dsw-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px; flex-wrap: wrap; gap: 24px; } .dsw-title { font-size: 28px; font-weight: 800; margin-bottom: 8px; background: linear-gradient(135deg, #10b981, #06b6d4); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } .dsw-subtitle { color: var(--sb-text-muted, #94a3b8); font-size: 14px; } .dsw-overall-progress { display: flex; align-items: center; gap: 24px; } .dsw-progress-circle { position: relative; width: 120px; height: 120px; } .dsw-progress-circle svg { transform: rotate(-90deg); } .dsw-progress-bg { fill: none; stroke: var(--sb-border, #2a2a3a); stroke-width: 8; } .dsw-progress-bar { fill: none; stroke: url(#gradient); stroke-width: 8; stroke-linecap: round; stroke-dasharray: 339; stroke-dashoffset: 339; transition: stroke-dashoffset 1.5s ease-out; } .dsw-progress-value { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 28px; font-weight: 800; color: var(--sb-green, #10b981); } .dsw-current-phase { text-align: left; } .dsw-phase-label { font-size: 11px; text-transform: uppercase; color: var(--sb-text-dim, #64748b); font-weight: 600; letter-spacing: 1px; } .dsw-phase-name { font-size: 18px; font-weight: 700; margin: 4px 0; } .dsw-phase-period { font-size: 13px; color: var(--sb-cyan, #06b6d4); font-family: 'JetBrains Mono', monospace; } .dsw-section-title { font-size: 20px; font-weight: 700; margin-bottom: 20px; color: var(--sb-text, #f1f5f9); } .dsw-milestones { margin-bottom: 40px; } .dsw-milestones-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 24px; } .dsw-milestone { background: var(--sb-bg, #0f1019); border: 1px solid var(--sb-border, #2a2a3a); border-radius: 12px; padding: 20px; transition: all 0.3s; } .dsw-milestone:hover { border-color: var(--sb-cyan, #06b6d4); transform: translateY(-2px); } .dsw-milestone-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .dsw-milestone-info { display: flex; align-items: center; gap: 10px; } .dsw-milestone-icon { font-size: 24px; } .dsw-milestone-name { font-size: 16px; font-weight: 700; } .dsw-milestone-stats { display: flex; align-items: center; gap: 12px; font-size: 14px; } .dsw-milestone-count { color: var(--sb-text-muted, #94a3b8); } .dsw-milestone-percent { font-weight: 700; } .dsw-progress-bar-container { height: 8px; background: rgba(255, 255, 255, 0.05); border-radius: 999px; overflow: hidden; margin-bottom: 16px; } .dsw-progress-bar-fill { height: 100%; width: 0; border-radius: 999px; transition: width 1s ease-out; } .dsw-item { display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 10px; background: rgba(255, 255, 255, 0.02); margin-bottom: 8px; border: 1px solid transparent; transition: all 0.2s; } .dsw-item:hover { border-color: rgba(255, 255, 255, 0.1); transform: translateX(4px); } .dsw-item.dsw-item-completed { border-color: rgba(16, 185, 129, 0.2); background: rgba(16, 185, 129, 0.05); } .dsw-item.dsw-item-in-progress { border-color: rgba(245, 158, 11, 0.2); background: rgba(245, 158, 11, 0.05); } .dsw-item.dsw-item-planned { border-color: rgba(59, 130, 246, 0.2); background: rgba(59, 130, 246, 0.05); } .dsw-item-icon { font-size: 18px; } .dsw-item-name { font-size: 14px; font-weight: 600; } .dsw-timeline { margin-bottom: 40px; } .dsw-timeline-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 24px; } .dsw-timeline-item { display: flex; gap: 16px; padding: 20px; background: var(--sb-bg, #0f1019); border: 1px solid var(--sb-border, #2a2a3a); border-radius: 12px; } .dsw-timeline-marker { display: flex; flex-direction: column; align-items: center; } .dsw-timeline-dot { width: 14px; height: 14px; border-radius: 50%; border: 3px solid #10b981; background: #1a1a24; } .dsw-timeline-line { flex: 1; width: 3px; background: linear-gradient(180deg, rgba(16, 185, 129, 0.5), rgba(59, 130, 246, 0.5)); margin: 8px 0; } .dsw-timeline-phase { font-size: 12px; font-weight: 700; text-transform: uppercase; color: var(--sb-text-dim, #64748b); letter-spacing: 1px; } .dsw-timeline-period { font-size: 13px; color: var(--sb-cyan, #06b6d4); font-family: 'JetBrains Mono', monospace; } .dsw-timeline-name { font-size: 16px; font-weight: 700; margin: 8px 0; } .dsw-timeline-progress { display: flex; align-items: center; gap: 12px; } .dsw-timeline-progress-bar { flex: 1; height: 6px; background: var(--sb-bg, #0f1019); border-radius: 3px; overflow: hidden; } .dsw-timeline-progress-fill { height: 100%; width: 0; background: linear-gradient(90deg, #10b981, #06b6d4); border-radius: 3px; transition: width 1s ease-out; } .dsw-timeline-progress-text { font-size: 12px; font-weight: 600; color: var(--sb-text-muted, #94a3b8); min-width: 40px; text-align: right; } .dsw-stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 16px; } .dsw-stat { background: var(--sb-bg, #0f1019); border: 1px solid var(--sb-border, #2a2a3a); border-radius: 12px; padding: 20px; text-align: center; transition: all 0.2s; } .dsw-stat:hover { border-color: var(--sb-cyan, #06b6d4); transform: translateY(-2px); } .dsw-stat-value { font-size: 32px; font-weight: 800; color: var(--sb-green, #10b981); font-family: 'JetBrains Mono', monospace; margin-bottom: 4px; } .dsw-stat-label { font-size: 12px; color: var(--sb-text-muted, #94a3b8); } @keyframes pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(249, 115, 22, 0.7); } 50% { box-shadow: 0 0 0 10px rgba(249, 115, 22, 0); } } @media (max-width: 768px) { .dev-status-widget { padding: 20px; } .dsw-header { flex-direction: column; align-items: flex-start; } .dsw-overall-progress { flex-direction: column; width: 100%; } .dsw-milestones-grid { grid-template-columns: 1fr; } .dsw-stats-grid { grid-template-columns: repeat(2, 1fr); } } `; document.head.appendChild(style); // Add SVG gradient if (!document.getElementById('dsw-gradient')) { const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '0'); svg.setAttribute('height', '0'); svg.innerHTML = ` `; svg.id = 'dsw-gradient'; document.body.appendChild(svg); } } });