'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 `
`;
},
/**
* Render milestones section
*/
renderMilestones() {
const milestonesHtml = Object.entries(this.milestones).map(([key, milestone]) => `
${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 ? '
' : ''}
`).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);
}
}
});