Redesign UI like Driver Navigator + fix CMD window
UI changes: - Top title bar with logo, app name, and system status LED - Toolbar with 4 icon tabs: Scan, Drivers, Download, System - Scan page with computer SVG illustration, stats, and big SCAN NOW button - Step indicator bar: Scan Devices > Review Drivers > Install Updates - Driver list with per-row progress bars, Download + Install buttons - "Update All Drivers" CTA bar at bottom when outdated drivers found - Windows Update tab with pending/installed sections - System Info tab with resource bars - Footer with About/Help buttons Backend fixes: - Add cmdutil.HiddenCommand() using CREATE_NO_WINDOW (0x08000000) - All PowerShell subprocesses now run without visible console window - Build with -ldflags "-H windowsgui" to hide main CMD window Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
16
internal/cmdutil/cmdutil.go
Normal file
16
internal/cmdutil/cmdutil.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package cmdutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HiddenCommand creates an exec.Cmd that runs without showing a console window.
|
||||||
|
// This prevents PowerShell/cmd flashing when the app runs as a GUI application.
|
||||||
|
func HiddenCommand(name string, args ...string) *exec.Cmd {
|
||||||
|
cmd := exec.Command(name, args...)
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
CreationFlags: 0x08000000, // CREATE_NO_WINDOW
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
@@ -2,9 +2,10 @@ package drivers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mumur/driver-booster/internal/cmdutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Driver struct {
|
type Driver struct {
|
||||||
@@ -63,7 +64,7 @@ func (s *Scanner) enumDriversPnP() []Driver {
|
|||||||
psScript := `
|
psScript := `
|
||||||
Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceName -ne $null } | Select-Object -First 100 DeviceName, DeviceClass, Manufacturer, DriverVersion, DriverDate, InfName, IsSigned, Status | ConvertTo-Json -Compress
|
Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceName -ne $null } | Select-Object -First 100 DeviceName, DeviceClass, Manufacturer, DriverVersion, DriverDate, InfName, IsSigned, Status | ConvertTo-Json -Compress
|
||||||
`
|
`
|
||||||
out, err := exec.Command("powershell", "-NoProfile", "-Command", psScript).Output()
|
out, err := cmdutil.HiddenCommand("powershell", "-NoProfile", "-Command", psScript).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []Driver{}
|
return []Driver{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package sysinfo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/mumur/driver-booster/internal/cmdutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -117,7 +118,7 @@ func getComputerName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCPUName() string {
|
func getCPUName() string {
|
||||||
out, err := exec.Command("powershell", "-NoProfile", "-Command",
|
out, err := cmdutil.HiddenCommand("powershell", "-NoProfile", "-Command",
|
||||||
"(Get-CimInstance Win32_Processor).Name").Output()
|
"(Get-CimInstance Win32_Processor).Name").Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "Unknown CPU"
|
return "Unknown CPU"
|
||||||
@@ -126,7 +127,7 @@ func getCPUName() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getWindowsProductName() string {
|
func getWindowsProductName() string {
|
||||||
out, err := exec.Command("powershell", "-NoProfile", "-Command",
|
out, err := cmdutil.HiddenCommand("powershell", "-NoProfile", "-Command",
|
||||||
"(Get-CimInstance Win32_OperatingSystem).Caption").Output()
|
"(Get-CimInstance Win32_OperatingSystem).Caption").Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "Windows"
|
return "Windows"
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ package winupdate
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os/exec"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mumur/driver-booster/internal/cmdutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
@@ -101,7 +102,7 @@ try {
|
|||||||
Pending = $pending
|
Pending = $pending
|
||||||
} | ConvertTo-Json -Depth 3 -Compress
|
} | ConvertTo-Json -Depth 3 -Compress
|
||||||
`
|
`
|
||||||
out, err := exec.Command("powershell", "-NoProfile", "-Command", psScript).Output()
|
out, err := cmdutil.HiddenCommand("powershell", "-NoProfile", "-Command", psScript).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Error = "Failed to check updates: " + err.Error()
|
result.Error = "Failed to check updates: " + err.Error()
|
||||||
result.CheckTime = time.Since(start).Round(time.Millisecond).String()
|
result.CheckTime = time.Since(start).Round(time.Millisecond).String()
|
||||||
@@ -193,7 +194,7 @@ if ($ToInstall.Count -gt 0) {
|
|||||||
Write-Output "No updates to install."
|
Write-Output "No updates to install."
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
out, err := exec.Command("powershell", "-NoProfile", "-Command", psScript).Output()
|
out, err := cmdutil.HiddenCommand("powershell", "-NoProfile", "-Command", psScript).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return InstallResult{
|
return InstallResult{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
|||||||
408
ui/app.js
408
ui/app.js
@@ -1,307 +1,266 @@
|
|||||||
/* ============================================================
|
/* ============================================================
|
||||||
Driver Booster Pro - Application Logic
|
Driver Booster Pro - Application Logic
|
||||||
|
Driver Navigator Style: tabs, driver rows, action buttons
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const App = {
|
var App = {
|
||||||
state: {
|
state: { sysInfo:null, drivers:null, updates:null },
|
||||||
sysInfo: null,
|
|
||||||
drivers: null,
|
|
||||||
updates: null,
|
|
||||||
},
|
|
||||||
|
|
||||||
init() {
|
init: function() {
|
||||||
this.setupNavigation();
|
this.setupTabs();
|
||||||
this.setupFilters();
|
this.setupFilters();
|
||||||
this.refreshSysInfo();
|
this.refreshSysInfo();
|
||||||
// Re-render Lucide icons after DOM mutations
|
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshIcons() {
|
refreshIcons: function() {
|
||||||
if (window.lucide) {
|
if (window.lucide) lucide.createIcons();
|
||||||
lucide.createIcons();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- Navigation ----
|
// ---- Tab Navigation ----
|
||||||
setupNavigation() {
|
setupTabs: function() {
|
||||||
document.querySelectorAll('.nav-item[data-page]').forEach(function(item) {
|
var self = this;
|
||||||
item.addEventListener('click', function() {
|
document.querySelectorAll('.toolbar-tab').forEach(function(tab) {
|
||||||
var page = item.dataset.page;
|
tab.addEventListener('click', function() {
|
||||||
document.querySelectorAll('.nav-item').forEach(function(n) { n.classList.remove('active'); });
|
var id = tab.dataset.tab;
|
||||||
item.classList.add('active');
|
document.querySelectorAll('.toolbar-tab').forEach(function(t){ t.classList.remove('active'); });
|
||||||
document.querySelectorAll('.page').forEach(function(p) { p.classList.remove('active'); });
|
tab.classList.add('active');
|
||||||
var target = document.getElementById('page-' + page);
|
document.querySelectorAll('.tab-page').forEach(function(p){ p.classList.remove('active'); });
|
||||||
|
var target = document.getElementById('tab-' + id);
|
||||||
if (target) target.classList.add('active');
|
if (target) target.classList.add('active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- Filters ----
|
// ---- Filter Pills ----
|
||||||
setupFilters() {
|
setupFilters: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
document.querySelectorAll('.filter-btn').forEach(function(btn) {
|
document.querySelectorAll('.pill').forEach(function(btn) {
|
||||||
btn.addEventListener('click', function() {
|
btn.addEventListener('click', function() {
|
||||||
document.querySelectorAll('.filter-btn').forEach(function(b) { b.classList.remove('active'); });
|
document.querySelectorAll('.pill').forEach(function(b){ b.classList.remove('active'); });
|
||||||
btn.classList.add('active');
|
btn.classList.add('active');
|
||||||
self.filterDrivers(btn.dataset.filter);
|
self.filterDrivers(btn.dataset.filter);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
filterDrivers(filter) {
|
filterDrivers: function(f) {
|
||||||
document.querySelectorAll('.driver-card').forEach(function(card) {
|
document.querySelectorAll('.drv-row').forEach(function(row) {
|
||||||
var show = filter === 'all' ||
|
var show = f === 'all' ||
|
||||||
(filter === 'outdated' && card.classList.contains('outdated')) ||
|
(f === 'outdated' && row.classList.contains('outdated')) ||
|
||||||
(filter === 'error' && card.classList.contains('error')) ||
|
(f === 'error' && row.classList.contains('error')) ||
|
||||||
(filter === 'signed' && card.dataset.signed === 'true');
|
(f === 'signed' && row.dataset.signed === 'true');
|
||||||
card.style.display = show ? '' : 'none';
|
row.style.display = show ? '' : 'none';
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- Loading ----
|
// ---- Loading ----
|
||||||
showLoading(text) {
|
showLoading: function(text) {
|
||||||
document.getElementById('loading-text').textContent = text;
|
document.getElementById('loading-text').textContent = text;
|
||||||
document.getElementById('loading-overlay').style.display = 'flex';
|
document.getElementById('loading-overlay').style.display = 'flex';
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
},
|
},
|
||||||
|
hideLoading: function() {
|
||||||
hideLoading() {
|
|
||||||
document.getElementById('loading-overlay').style.display = 'none';
|
document.getElementById('loading-overlay').style.display = 'none';
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- System Info ----
|
// ---- System Info ----
|
||||||
async refreshSysInfo() {
|
refreshSysInfo: function() {
|
||||||
|
var self = this;
|
||||||
this.showLoading('Collecting system information...');
|
this.showLoading('Collecting system information...');
|
||||||
try {
|
fetch('/api/sysinfo').then(function(r){ return r.json(); }).then(function(info) {
|
||||||
var res = await fetch('/api/sysinfo');
|
self.state.sysInfo = info;
|
||||||
var info = await res.json();
|
self.renderSysInfo(info);
|
||||||
this.state.sysInfo = info;
|
self.hideLoading();
|
||||||
this.renderSysInfo(info);
|
}).catch(function(e) {
|
||||||
this.updateDashboardResources(info);
|
console.error(e);
|
||||||
} catch (e) {
|
self.hideLoading();
|
||||||
console.error('Failed to get sysinfo:', e);
|
});
|
||||||
}
|
|
||||||
this.hideLoading();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderSysInfo(info) {
|
renderSysInfo: function(d) {
|
||||||
this.setText('sys-name', info.computerName);
|
this.set('sys-name', d.computerName);
|
||||||
this.setText('sys-os', info.osName);
|
this.set('sys-os', d.osName);
|
||||||
this.setText('sys-version', info.osVersion);
|
this.set('sys-version', d.osVersion);
|
||||||
this.setText('sys-build', info.osBuild);
|
this.set('sys-build', d.osBuild);
|
||||||
this.setText('sys-arch', info.architecture);
|
this.set('sys-arch', d.architecture);
|
||||||
this.setText('sys-cpu', info.cpuName);
|
this.set('sys-cpu', d.cpuName);
|
||||||
this.setText('sys-cores', info.cpuCores);
|
this.set('sys-cores', d.cpuCores);
|
||||||
this.setText('sys-ram-total', info.totalRam);
|
this.set('sys-ram-total', d.totalRam);
|
||||||
this.setText('sys-ram-used', info.usedRam);
|
this.set('sys-ram-used', d.usedRam);
|
||||||
this.setText('sys-ram-free', info.freeRam);
|
this.set('sys-ram-free', d.freeRam);
|
||||||
this.setText('sys-ram-pct', (info.ramPercent || 0) + '%');
|
this.set('sys-ram-pct', (d.ramPercent||0)+'%');
|
||||||
this.setText('sys-disk-total', info.diskTotal);
|
this.set('sys-disk-total', d.diskTotal);
|
||||||
this.setText('sys-disk-used', info.diskUsed);
|
this.set('sys-disk-used', d.diskUsed);
|
||||||
this.setText('sys-disk-free', info.diskFree);
|
this.set('sys-disk-free', d.diskFree);
|
||||||
this.setText('sys-disk-pct', (info.diskPercent || 0) + '%');
|
this.set('sys-disk-pct', (d.diskPercent||0)+'%');
|
||||||
|
var rb = document.getElementById('sys-ram-bar');
|
||||||
|
var db = document.getElementById('sys-disk-bar');
|
||||||
|
if(rb) rb.style.width = (d.ramPercent||0)+'%';
|
||||||
|
if(db) db.style.width = (d.diskPercent||0)+'%';
|
||||||
},
|
},
|
||||||
|
|
||||||
updateDashboardResources(info) {
|
// ---- Driver Scan ----
|
||||||
this.setText('dash-ram-percent', (info.ramPercent || 0) + '%');
|
scanDrivers: function() {
|
||||||
this.setText('dash-ram-detail', (info.usedRam || '--') + ' / ' + (info.totalRam || '--'));
|
var self = this;
|
||||||
document.getElementById('dash-ram-bar').style.width = (info.ramPercent || 0) + '%';
|
|
||||||
this.setText('dash-disk-detail', (info.diskUsed || '--') + ' / ' + (info.diskTotal || '--'));
|
|
||||||
document.getElementById('dash-disk-bar').style.width = (info.diskPercent || 0) + '%';
|
|
||||||
|
|
||||||
// Warn color for high usage
|
|
||||||
var ramBar = document.getElementById('dash-ram-bar');
|
|
||||||
var diskBar = document.getElementById('dash-disk-bar');
|
|
||||||
if (info.ramPercent > 80) {
|
|
||||||
ramBar.style.background = 'linear-gradient(90deg, #f59e0b, #ef4444)';
|
|
||||||
} else {
|
|
||||||
ramBar.style.background = '';
|
|
||||||
}
|
|
||||||
if (info.diskPercent > 85) {
|
|
||||||
diskBar.style.background = 'linear-gradient(90deg, #f59e0b, #ef4444)';
|
|
||||||
} else {
|
|
||||||
diskBar.style.background = '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// ---- Drivers ----
|
|
||||||
async scanDrivers() {
|
|
||||||
this.showLoading('Scanning drivers... This may take a moment.');
|
this.showLoading('Scanning drivers... This may take a moment.');
|
||||||
try {
|
// Switch to drivers tab
|
||||||
var res = await fetch('/api/drivers/scan');
|
document.querySelectorAll('.toolbar-tab').forEach(function(t){ t.classList.remove('active'); });
|
||||||
var result = await res.json();
|
document.querySelector('[data-tab="drivers"]').classList.add('active');
|
||||||
this.state.drivers = result;
|
document.querySelectorAll('.tab-page').forEach(function(p){ p.classList.remove('active'); });
|
||||||
this.renderDrivers(result);
|
document.getElementById('tab-drivers').classList.add('active');
|
||||||
this.updateDashboardDrivers(result);
|
|
||||||
} catch (e) {
|
// Update steps
|
||||||
console.error('Failed to scan drivers:', e);
|
this.setStep(2);
|
||||||
}
|
|
||||||
this.hideLoading();
|
fetch('/api/drivers/scan').then(function(r){ return r.json(); }).then(function(result) {
|
||||||
|
self.state.drivers = result;
|
||||||
|
self.renderDrivers(result);
|
||||||
|
self.updateScanStats(result);
|
||||||
|
self.hideLoading();
|
||||||
|
}).catch(function(e) {
|
||||||
|
console.error(e);
|
||||||
|
self.hideLoading();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderDrivers(result) {
|
updateScanStats: function(r) {
|
||||||
document.getElementById('driver-summary').style.display = 'flex';
|
this.set('scan-stat-total', r.totalCount);
|
||||||
document.getElementById('driver-filters').style.display = 'flex';
|
this.set('scan-stat-outdated', r.outdatedCount);
|
||||||
this.setText('drv-total', result.totalCount);
|
this.set('scan-stat-errors', r.errorCount);
|
||||||
this.setText('drv-outdated', result.outdatedCount);
|
},
|
||||||
this.setText('drv-errors', result.errorCount);
|
|
||||||
this.setText('drv-time', result.scanTime);
|
renderDrivers: function(result) {
|
||||||
|
document.getElementById('driver-result-count').style.display = 'block';
|
||||||
|
document.getElementById('driver-filter-strip').style.display = 'flex';
|
||||||
|
this.set('drv-total-2', result.totalCount);
|
||||||
|
this.set('drv-outdated-2', result.outdatedCount);
|
||||||
|
this.set('drv-time-2', result.scanTime);
|
||||||
|
|
||||||
var list = document.getElementById('driver-list');
|
var list = document.getElementById('driver-list');
|
||||||
if (!result.drivers || result.drivers.length === 0) {
|
if (!result.drivers || result.drivers.length === 0) {
|
||||||
list.innerHTML =
|
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="search-x"></i><p>No drivers found</p></div>';
|
||||||
'<div class="empty-state">' +
|
|
||||||
'<div class="empty-icon"><i data-lucide="search-x"></i></div>' +
|
|
||||||
'<h3>No Drivers Found</h3>' +
|
|
||||||
'<p>No driver information was returned.</p>' +
|
|
||||||
'</div>';
|
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
list.innerHTML = result.drivers.map(function(d) {
|
list.innerHTML = result.drivers.map(function(d) {
|
||||||
var classes = ['driver-card'];
|
var cls = ['drv-row'];
|
||||||
if (d.needsUpdate) classes.push('outdated');
|
if (d.needsUpdate) cls.push('outdated');
|
||||||
if (d.status === 'Error' || d.status === 'Degraded') classes.push('error');
|
if (d.status === 'Error' || d.status === 'Degraded') cls.push('error');
|
||||||
|
|
||||||
var iconName = self.getClassIconName(d.deviceClass);
|
var icon = self.driverIcon(d.deviceClass);
|
||||||
|
var barClass = d.needsUpdate ? 'warn' : (d.status === 'Error' ? 'err' : 'ok');
|
||||||
|
|
||||||
var badges = '';
|
var signBadge = d.isSigned
|
||||||
if (d.isSigned) {
|
? '<span class="drv-badge signed"><i data-lucide="shield-check"></i> Signed</span>'
|
||||||
badges += '<span class="badge badge-signed"><i data-lucide="shield-check"></i> Signed</span>';
|
: '<span class="drv-badge unsigned"><i data-lucide="shield-x"></i></span>';
|
||||||
} else {
|
|
||||||
badges += '<span class="badge badge-unsigned"><i data-lucide="shield-x"></i> Unsigned</span>';
|
|
||||||
}
|
|
||||||
if (d.needsUpdate) {
|
|
||||||
badges += '<span class="badge badge-outdated"><i data-lucide="clock"></i> Outdated</span>';
|
|
||||||
} else {
|
|
||||||
badges += '<span class="badge badge-ok"><i data-lucide="circle-check"></i> OK</span>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<div class="' + classes.join(' ') + '" data-signed="' + d.isSigned + '">' +
|
var actionBtn = d.needsUpdate
|
||||||
'<div class="driver-class-icon"><i data-lucide="' + iconName + '"></i></div>' +
|
? '<button class="drv-btn install-btn"><i data-lucide="download"></i> Download</button>' +
|
||||||
'<div class="driver-info">' +
|
'<button class="drv-btn"><i data-lucide="play"></i> Install</button>'
|
||||||
'<div class="driver-name">' + self.esc(d.deviceName) + '</div>' +
|
: '<button class="drv-btn installed-btn"><i data-lucide="circle-check"></i> Up to date</button>';
|
||||||
'<div class="driver-meta">' +
|
|
||||||
self.esc(d.manufacturer || 'Unknown') +
|
return '<div class="' + cls.join(' ') + '" data-signed="' + d.isSigned + '">' +
|
||||||
' <span class="driver-meta-sep">·</span> v' + self.esc(d.driverVersion || '?') +
|
'<div class="drv-icon"><i data-lucide="' + icon + '"></i></div>' +
|
||||||
' <span class="driver-meta-sep">·</span> ' + self.esc(d.driverDate) +
|
'<div class="drv-info">' +
|
||||||
'</div>' +
|
'<div class="drv-name">' + self.esc(d.deviceName) + '</div>' +
|
||||||
|
'<div class="drv-meta">' + self.esc(d.manufacturer||'Unknown') + ' · v' + self.esc(d.driverVersion||'?') + ' · ' + self.esc(d.driverDate) + ' ' + signBadge + '</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div class="driver-badges">' + badges + '</div>' +
|
'<div class="drv-progress">' +
|
||||||
|
'<div class="drv-bar"><div class="drv-bar-fill ' + barClass + '"></div></div>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="drv-actions">' + actionBtn + '</div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
|
// Show CTA if there are outdated drivers
|
||||||
|
var cta = document.getElementById('cta-update-all');
|
||||||
|
if (result.outdatedCount > 0) {
|
||||||
|
cta.style.display = 'flex';
|
||||||
|
this.set('cta-count', result.outdatedCount);
|
||||||
|
} else {
|
||||||
|
cta.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
},
|
},
|
||||||
|
|
||||||
updateDashboardDrivers(result) {
|
driverIcon: function(cls) {
|
||||||
this.setText('dash-driver-count', result.totalCount);
|
|
||||||
this.setText('dash-outdated-count', result.outdatedCount);
|
|
||||||
},
|
|
||||||
|
|
||||||
getClassIconName(cls) {
|
|
||||||
if (!cls) return 'package';
|
if (!cls) return 'package';
|
||||||
var upper = cls.toUpperCase();
|
var u = cls.toUpperCase();
|
||||||
var map = {
|
var m = {
|
||||||
'DISPLAY': 'monitor',
|
'DISPLAY':'monitor','MEDIA':'volume-2','AUDIO':'volume-2','SOUND':'volume-2',
|
||||||
'MEDIA': 'volume-2',
|
'NET':'wifi','NETWORK':'wifi','USB':'usb','HID':'mouse','KEYBOARD':'keyboard',
|
||||||
'AUDIO': 'volume-2',
|
'DISK':'hard-drive','STORAGE':'hard-drive','PROCESSOR':'cpu','SYSTEM':'settings',
|
||||||
'SOUND': 'volume-2',
|
'BLUETOOTH':'bluetooth','CAMERA':'camera','IMAGE':'camera','PRINT':'printer',
|
||||||
'NET': 'wifi',
|
'BATTERY':'battery-charging','FIRMWARE':'circuit-board','SECURITY':'shield',
|
||||||
'NETWORK': 'wifi',
|
'SENSOR':'thermometer'
|
||||||
'USB': 'usb',
|
|
||||||
'HID': 'mouse',
|
|
||||||
'KEYBOARD': 'keyboard',
|
|
||||||
'DISK': 'hard-drive',
|
|
||||||
'STORAGE': 'hard-drive',
|
|
||||||
'PROCESSOR': 'cpu',
|
|
||||||
'SYSTEM': 'settings',
|
|
||||||
'BLUETOOTH': 'bluetooth',
|
|
||||||
'CAMERA': 'camera',
|
|
||||||
'IMAGE': 'camera',
|
|
||||||
'PRINT': 'printer',
|
|
||||||
'BATTERY': 'battery-charging',
|
|
||||||
'BIOMETRIC': 'fingerprint',
|
|
||||||
'FIRMWARE': 'circuit-board',
|
|
||||||
'SECURITY': 'shield',
|
|
||||||
'SENSOR': 'thermometer',
|
|
||||||
};
|
};
|
||||||
for (var key in map) {
|
for (var k in m) { if (u.indexOf(k) !== -1) return m[k]; }
|
||||||
if (upper.indexOf(key) !== -1) return map[key];
|
|
||||||
}
|
|
||||||
return 'package';
|
return 'package';
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- Updates ----
|
// ---- Windows Update ----
|
||||||
async checkUpdates() {
|
checkUpdates: function() {
|
||||||
|
var self = this;
|
||||||
this.showLoading('Checking for Windows updates...');
|
this.showLoading('Checking for Windows updates...');
|
||||||
try {
|
// Switch to updates tab
|
||||||
var res = await fetch('/api/updates/check');
|
document.querySelectorAll('.toolbar-tab').forEach(function(t){ t.classList.remove('active'); });
|
||||||
var result = await res.json();
|
document.querySelector('[data-tab="updates"]').classList.add('active');
|
||||||
this.state.updates = result;
|
document.querySelectorAll('.tab-page').forEach(function(p){ p.classList.remove('active'); });
|
||||||
this.renderUpdates(result);
|
document.getElementById('tab-updates').classList.add('active');
|
||||||
this.setText('dash-update-count', result.pendingCount);
|
|
||||||
} catch (e) {
|
fetch('/api/updates/check').then(function(r){ return r.json(); }).then(function(result) {
|
||||||
console.error('Failed to check updates:', e);
|
self.state.updates = result;
|
||||||
}
|
self.renderUpdates(result);
|
||||||
this.hideLoading();
|
self.hideLoading();
|
||||||
|
}).catch(function(e) {
|
||||||
|
console.error(e);
|
||||||
|
self.hideLoading();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renderUpdates(result) {
|
renderUpdates: function(result) {
|
||||||
var list = document.getElementById('update-list');
|
var list = document.getElementById('update-list');
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
list.innerHTML =
|
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="alert-circle"></i><p style="color:var(--red)">' + this.esc(result.error) + '</p></div>';
|
||||||
'<div class="empty-state">' +
|
|
||||||
'<div class="empty-icon"><i data-lucide="alert-circle"></i></div>' +
|
|
||||||
'<h3>Error</h3>' +
|
|
||||||
'<p style="color:var(--danger)">' + this.esc(result.error) + '</p>' +
|
|
||||||
'</div>';
|
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.updates || result.updates.length === 0) {
|
if (!result.updates || result.updates.length === 0) {
|
||||||
list.innerHTML =
|
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="circle-check"></i><p>Your system is fully up to date!</p></div>';
|
||||||
'<div class="empty-state">' +
|
|
||||||
'<div class="empty-icon"><i data-lucide="circle-check"></i></div>' +
|
|
||||||
'<h3>All Up to Date</h3>' +
|
|
||||||
'<p>Your system is fully updated.</p>' +
|
|
||||||
'</div>';
|
|
||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var pending = result.updates.filter(function(u) { return !u.isInstalled; });
|
var pending = result.updates.filter(function(u){return !u.isInstalled;});
|
||||||
var installed = result.updates.filter(function(u) { return u.isInstalled; });
|
var installed = result.updates.filter(function(u){return u.isInstalled;});
|
||||||
var self = this;
|
var self = this;
|
||||||
var html = '';
|
var html = '';
|
||||||
|
|
||||||
if (pending.length > 0) {
|
if (pending.length > 0) {
|
||||||
html += '<div class="update-section-title pending"><i data-lucide="download"></i> Pending Updates (' + pending.length + ')</div>';
|
html += '<div class="upd-section pend"><i data-lucide="download"></i> Pending (' + pending.length + ')</div>';
|
||||||
html += pending.map(function(u) {
|
html += pending.map(function(u) {
|
||||||
return '<div class="update-card pending">' +
|
return '<div class="upd-row pending">' +
|
||||||
'<div class="update-title">' + self.esc(u.title) + '</div>' +
|
'<div class="upd-title">' + self.esc(u.title) + '</div>' +
|
||||||
'<div class="update-meta">' +
|
'<div class="upd-meta">' +
|
||||||
(u.kbArticle ? '<span class="update-tag"><i data-lucide="file-text"></i> ' + self.esc(u.kbArticle) + '</span>' : '') +
|
(u.kbArticle ? '<span class="upd-tag"><i data-lucide="file-text"></i> '+self.esc(u.kbArticle)+'</span>' : '') +
|
||||||
(u.category ? '<span class="update-tag"><i data-lucide="folder"></i> ' + self.esc(u.category) + '</span>' : '') +
|
(u.category ? '<span class="upd-tag"><i data-lucide="folder"></i> '+self.esc(u.category)+'</span>' : '') +
|
||||||
(u.size ? '<span class="update-tag"><i data-lucide="hard-drive"></i> ' + self.esc(u.size) + '</span>' : '') +
|
(u.size ? '<span class="upd-tag"><i data-lucide="hard-drive"></i> '+self.esc(u.size)+'</span>' : '') +
|
||||||
(u.severity && u.severity !== 'Unspecified' ? '<span class="update-tag"><i data-lucide="alert-triangle"></i> ' + self.esc(u.severity) + '</span>' : '') +
|
(u.severity && u.severity !== 'Unspecified' ? '<span class="upd-tag"><i data-lucide="alert-triangle"></i> '+self.esc(u.severity)+'</span>' : '') +
|
||||||
(u.isMandatory ? '<span class="update-tag" style="color:var(--danger)"><i data-lucide="alert-circle"></i> Mandatory</span>' : '') +
|
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>';
|
'</div>';
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (installed.length > 0) {
|
if (installed.length > 0) {
|
||||||
html += '<div class="update-section-title installed"><i data-lucide="check-circle"></i> Recently Installed (' + installed.length + ')</div>';
|
html += '<div class="upd-section inst"><i data-lucide="check-circle"></i> Recently Installed (' + installed.length + ')</div>';
|
||||||
html += installed.map(function(u) {
|
html += installed.map(function(u) {
|
||||||
return '<div class="update-card installed">' +
|
return '<div class="upd-row done"><div class="upd-title">' + self.esc(u.title) + '</div></div>';
|
||||||
'<div class="update-title">' + self.esc(u.title) + '</div>' +
|
|
||||||
'</div>';
|
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,21 +268,28 @@ const App = {
|
|||||||
this.refreshIcons();
|
this.refreshIcons();
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---- Utility ----
|
// ---- Step bar ----
|
||||||
setText(id, value) {
|
setStep: function(n) {
|
||||||
var el = document.getElementById(id);
|
for (var i = 1; i <= 3; i++) {
|
||||||
if (el) el.textContent = (value != null && value !== '') ? value : '--';
|
var el = document.getElementById('step-' + i);
|
||||||
|
if (!el) continue;
|
||||||
|
el.classList.remove('active', 'done');
|
||||||
|
if (i < n) el.classList.add('done');
|
||||||
|
if (i === n) el.classList.add('active');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
esc(str) {
|
// ---- Helpers ----
|
||||||
if (!str) return '';
|
set: function(id, val) {
|
||||||
var div = document.createElement('div');
|
var el = document.getElementById(id);
|
||||||
div.textContent = str;
|
if (el) el.textContent = (val != null && val !== '') ? val : '--';
|
||||||
return div.innerHTML;
|
|
||||||
},
|
},
|
||||||
|
esc: function(s) {
|
||||||
|
if (!s) return '';
|
||||||
|
var d = document.createElement('div');
|
||||||
|
d.textContent = s;
|
||||||
|
return d.innerHTML;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Boot
|
document.addEventListener('DOMContentLoaded', function() { App.init(); });
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
App.init();
|
|
||||||
});
|
|
||||||
|
|||||||
512
ui/index.html
512
ui/index.html
@@ -8,342 +8,257 @@
|
|||||||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Animated background -->
|
|
||||||
<div class="bg-grid"></div>
|
|
||||||
<div class="bg-glow bg-glow-1"></div>
|
|
||||||
<div class="bg-glow bg-glow-2"></div>
|
|
||||||
|
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<!-- Sidebar -->
|
<!-- Title Bar -->
|
||||||
<nav class="sidebar">
|
<div class="titlebar">
|
||||||
<div class="sidebar-header">
|
<div class="titlebar-left">
|
||||||
<div class="logo">
|
<div class="app-logo">
|
||||||
<div class="logo-icon">
|
<i data-lucide="shield-check"></i>
|
||||||
<i data-lucide="shield-check"></i>
|
</div>
|
||||||
</div>
|
<div class="app-title">
|
||||||
<div class="logo-text-wrap">
|
<span class="app-name">DRIVER BOOSTER</span>
|
||||||
<span class="logo-text">Driver Booster</span>
|
<span class="app-edition">PRO</span>
|
||||||
<span class="logo-sub">System Toolkit</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="titlebar-right">
|
||||||
|
<div class="sys-status" id="sys-status">
|
||||||
|
<div class="status-led"></div>
|
||||||
|
<span>System Protected</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="nav-section-label">Main</div>
|
<!-- Toolbar Tabs -->
|
||||||
<ul class="nav-items">
|
<div class="toolbar">
|
||||||
<li class="nav-item active" data-page="dashboard">
|
<button class="toolbar-tab active" data-tab="scan">
|
||||||
<i data-lucide="layout-dashboard"></i>
|
<div class="tab-icon-wrap scan-icon-wrap">
|
||||||
<span>Dashboard</span>
|
|
||||||
<div class="nav-indicator"></div>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" data-page="drivers">
|
|
||||||
<i data-lucide="cpu"></i>
|
|
||||||
<span>Drivers</span>
|
|
||||||
<div class="nav-indicator"></div>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" data-page="updates">
|
|
||||||
<i data-lucide="download-cloud"></i>
|
|
||||||
<span>Windows Update</span>
|
|
||||||
<div class="nav-indicator"></div>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item" data-page="system">
|
|
||||||
<i data-lucide="monitor"></i>
|
|
||||||
<span>System Info</span>
|
|
||||||
<div class="nav-indicator"></div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="nav-section-label">Tools</div>
|
|
||||||
<ul class="nav-items">
|
|
||||||
<li class="nav-item" data-page="dashboard" onclick="App.scanDrivers()">
|
|
||||||
<i data-lucide="scan-search"></i>
|
<i data-lucide="scan-search"></i>
|
||||||
<span>Quick Scan</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="sidebar-footer">
|
|
||||||
<div class="app-status" id="app-status">
|
|
||||||
<div class="status-dot online"></div>
|
|
||||||
<span>System Online</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="version-badge">v1.0.0</div>
|
<span>Scan</span>
|
||||||
</div>
|
</button>
|
||||||
</nav>
|
<button class="toolbar-tab" data-tab="drivers">
|
||||||
|
<div class="tab-icon-wrap drivers-icon-wrap">
|
||||||
<!-- Main Content -->
|
<i data-lucide="cpu"></i>
|
||||||
<main class="content">
|
|
||||||
<!-- Dashboard Page -->
|
|
||||||
<div class="page active" id="page-dashboard">
|
|
||||||
<div class="page-header">
|
|
||||||
<div>
|
|
||||||
<h1><i data-lucide="layout-dashboard" class="page-icon"></i> Dashboard</h1>
|
|
||||||
<p class="subtitle">Monitor your system health at a glance</p>
|
|
||||||
</div>
|
|
||||||
<div class="header-actions">
|
|
||||||
<button class="icon-btn" onclick="App.refreshSysInfo()" title="Refresh">
|
|
||||||
<i data-lucide="refresh-cw"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span>Drivers</span>
|
||||||
<div class="stats-grid">
|
</button>
|
||||||
<div class="stat-card stat-drivers">
|
<button class="toolbar-tab" data-tab="updates">
|
||||||
<div class="stat-card-bg"></div>
|
<div class="tab-icon-wrap updates-icon-wrap">
|
||||||
<div class="stat-icon">
|
<i data-lucide="download-cloud"></i>
|
||||||
<i data-lucide="cpu"></i>
|
|
||||||
</div>
|
|
||||||
<div class="stat-info">
|
|
||||||
<span class="stat-value" id="dash-driver-count">--</span>
|
|
||||||
<span class="stat-label">Total Drivers</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-trend">
|
|
||||||
<i data-lucide="layers"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-card stat-outdated">
|
|
||||||
<div class="stat-card-bg"></div>
|
|
||||||
<div class="stat-icon">
|
|
||||||
<i data-lucide="alert-triangle"></i>
|
|
||||||
</div>
|
|
||||||
<div class="stat-info">
|
|
||||||
<span class="stat-value" id="dash-outdated-count">--</span>
|
|
||||||
<span class="stat-label">Outdated</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-trend">
|
|
||||||
<i data-lucide="triangle-alert"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-card stat-updates">
|
|
||||||
<div class="stat-card-bg"></div>
|
|
||||||
<div class="stat-icon">
|
|
||||||
<i data-lucide="download-cloud"></i>
|
|
||||||
</div>
|
|
||||||
<div class="stat-info">
|
|
||||||
<span class="stat-value" id="dash-update-count">--</span>
|
|
||||||
<span class="stat-label">Pending Updates</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-trend">
|
|
||||||
<i data-lucide="cloud-download"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="stat-card stat-ram">
|
|
||||||
<div class="stat-card-bg"></div>
|
|
||||||
<div class="stat-icon">
|
|
||||||
<i data-lucide="memory-stick"></i>
|
|
||||||
</div>
|
|
||||||
<div class="stat-info">
|
|
||||||
<span class="stat-value" id="dash-ram-percent">--</span>
|
|
||||||
<span class="stat-label">RAM Usage</span>
|
|
||||||
</div>
|
|
||||||
<div class="stat-trend">
|
|
||||||
<i data-lucide="activity"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<span>Download</span>
|
||||||
|
</button>
|
||||||
|
<button class="toolbar-tab" data-tab="system">
|
||||||
|
<div class="tab-icon-wrap settings-icon-wrap">
|
||||||
|
<i data-lucide="monitor-cog"></i>
|
||||||
|
</div>
|
||||||
|
<span>System</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="dashboard-panels">
|
<!-- Content Area -->
|
||||||
<div class="panel glass-panel">
|
<div class="content-area">
|
||||||
<div class="panel-header">
|
|
||||||
<div class="panel-title">
|
<!-- ====== SCAN TAB ====== -->
|
||||||
<i data-lucide="zap"></i>
|
<div class="tab-page active" id="tab-scan">
|
||||||
<h3>Quick Actions</h3>
|
<div class="scan-hero">
|
||||||
|
<div class="scan-illustration">
|
||||||
|
<!-- Computer SVG Illustration -->
|
||||||
|
<svg viewBox="0 0 200 180" class="computer-svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="screen-grad" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#1e40af"/>
|
||||||
|
<stop offset="100%" stop-color="#3b82f6"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="body-grad" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#e2e8f0"/>
|
||||||
|
<stop offset="100%" stop-color="#cbd5e1"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="shield-grad" x1="0" y1="0" x2="1" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#10b981"/>
|
||||||
|
<stop offset="100%" stop-color="#059669"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<!-- Monitor -->
|
||||||
|
<rect x="30" y="10" width="140" height="100" rx="8" fill="url(#body-grad)" stroke="#94a3b8" stroke-width="2"/>
|
||||||
|
<rect x="38" y="18" width="124" height="76" rx="4" fill="url(#screen-grad)"/>
|
||||||
|
<!-- Screen content lines -->
|
||||||
|
<rect x="50" y="34" width="60" height="4" rx="2" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<rect x="50" y="44" width="80" height="4" rx="2" fill="rgba(255,255,255,0.2)"/>
|
||||||
|
<rect x="50" y="54" width="45" height="4" rx="2" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<rect x="50" y="64" width="70" height="4" rx="2" fill="rgba(255,255,255,0.2)"/>
|
||||||
|
<rect x="50" y="74" width="55" height="4" rx="2" fill="rgba(255,255,255,0.3)"/>
|
||||||
|
<!-- Check marks -->
|
||||||
|
<circle cx="46" cy="36" r="3" fill="#10b981"/>
|
||||||
|
<circle cx="46" cy="46" r="3" fill="#10b981"/>
|
||||||
|
<circle cx="46" cy="56" r="3" fill="#10b981"/>
|
||||||
|
<circle cx="46" cy="66" r="3" fill="#f59e0b"/>
|
||||||
|
<circle cx="46" cy="76" r="3" fill="#ef4444"/>
|
||||||
|
<!-- Stand -->
|
||||||
|
<rect x="85" y="110" width="30" height="12" rx="2" fill="#94a3b8"/>
|
||||||
|
<rect x="70" y="120" width="60" height="6" rx="3" fill="#94a3b8"/>
|
||||||
|
<!-- Shield overlay -->
|
||||||
|
<path d="M145 55 L145 35 C145 35 155 30 165 35 C175 30 185 35 185 35 L185 55 C185 70 165 82 165 82 C165 82 145 70 145 55Z" fill="url(#shield-grad)" opacity="0.9"/>
|
||||||
|
<polyline points="157,55 163,62 175,48" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="scan-info">
|
||||||
|
<h2>Scan Your System</h2>
|
||||||
|
<p>Detect outdated, missing, and faulty drivers. Keep your PC running at peak performance.</p>
|
||||||
|
<div class="scan-stats" id="scan-stats">
|
||||||
|
<div class="mini-stat">
|
||||||
|
<i data-lucide="cpu"></i>
|
||||||
|
<span id="scan-stat-total">--</span>
|
||||||
|
<label>Drivers</label>
|
||||||
|
</div>
|
||||||
|
<div class="mini-stat warn">
|
||||||
|
<i data-lucide="alert-triangle"></i>
|
||||||
|
<span id="scan-stat-outdated">--</span>
|
||||||
|
<label>Outdated</label>
|
||||||
|
</div>
|
||||||
|
<div class="mini-stat danger">
|
||||||
|
<i data-lucide="x-circle"></i>
|
||||||
|
<span id="scan-stat-errors">--</span>
|
||||||
|
<label>Errors</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="quick-actions">
|
<button class="big-scan-btn" id="btn-scan" onclick="App.scanDrivers()">
|
||||||
<button class="action-btn primary" onclick="App.scanDrivers()">
|
|
||||||
<div class="action-btn-icon"><i data-lucide="scan-search"></i></div>
|
|
||||||
<div class="action-btn-text">
|
|
||||||
<span class="action-btn-title">Scan Drivers</span>
|
|
||||||
<span class="action-btn-desc">Detect outdated & missing drivers</span>
|
|
||||||
</div>
|
|
||||||
<i data-lucide="chevron-right" class="action-arrow"></i>
|
|
||||||
</button>
|
|
||||||
<button class="action-btn blue" onclick="App.checkUpdates()">
|
|
||||||
<div class="action-btn-icon"><i data-lucide="cloud-download"></i></div>
|
|
||||||
<div class="action-btn-text">
|
|
||||||
<span class="action-btn-title">Check Updates</span>
|
|
||||||
<span class="action-btn-desc">Search for Windows updates</span>
|
|
||||||
</div>
|
|
||||||
<i data-lucide="chevron-right" class="action-arrow"></i>
|
|
||||||
</button>
|
|
||||||
<button class="action-btn green" onclick="App.refreshSysInfo()">
|
|
||||||
<div class="action-btn-icon"><i data-lucide="monitor-check"></i></div>
|
|
||||||
<div class="action-btn-text">
|
|
||||||
<span class="action-btn-title">System Health</span>
|
|
||||||
<span class="action-btn-desc">Refresh system information</span>
|
|
||||||
</div>
|
|
||||||
<i data-lucide="chevron-right" class="action-arrow"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel glass-panel">
|
|
||||||
<div class="panel-header">
|
|
||||||
<div class="panel-title">
|
|
||||||
<i data-lucide="gauge"></i>
|
|
||||||
<h3>System Resources</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="resource-bars">
|
|
||||||
<div class="resource-item">
|
|
||||||
<div class="resource-header">
|
|
||||||
<div class="resource-label-group">
|
|
||||||
<i data-lucide="memory-stick" class="resource-icon"></i>
|
|
||||||
<span class="resource-name">Memory (RAM)</span>
|
|
||||||
</div>
|
|
||||||
<span class="resource-value" id="dash-ram-detail">-- / --</span>
|
|
||||||
</div>
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-fill ram-fill" id="dash-ram-bar" style="width: 0%">
|
|
||||||
<div class="progress-shine"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="resource-item">
|
|
||||||
<div class="resource-header">
|
|
||||||
<div class="resource-label-group">
|
|
||||||
<i data-lucide="hard-drive" class="resource-icon"></i>
|
|
||||||
<span class="resource-name">Storage (C:)</span>
|
|
||||||
</div>
|
|
||||||
<span class="resource-value" id="dash-disk-detail">-- / --</span>
|
|
||||||
</div>
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-fill disk-fill" id="dash-disk-bar" style="width: 0%">
|
|
||||||
<div class="progress-shine"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Drivers Page -->
|
|
||||||
<div class="page" id="page-drivers">
|
|
||||||
<div class="page-header">
|
|
||||||
<div>
|
|
||||||
<h1><i data-lucide="cpu" class="page-icon"></i> Driver Manager</h1>
|
|
||||||
<p class="subtitle">Scan and manage your system drivers</p>
|
|
||||||
</div>
|
|
||||||
<div class="header-actions">
|
|
||||||
<button class="action-btn primary compact" onclick="App.scanDrivers()">
|
|
||||||
<i data-lucide="scan-search"></i>
|
<i data-lucide="scan-search"></i>
|
||||||
<span>Scan Now</span>
|
<span>SCAN NOW</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="driver-summary glass-panel" id="driver-summary" style="display:none">
|
|
||||||
<div class="summary-item">
|
<!-- Step Indicator -->
|
||||||
<i data-lucide="layers" class="sum-icon"></i>
|
<div class="step-bar">
|
||||||
<strong id="drv-total">0</strong> <span>Total</span>
|
<div class="step active" id="step-1">
|
||||||
|
<div class="step-num">1</div>
|
||||||
|
<span>Scan Devices</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-item warning">
|
<div class="step-line"></div>
|
||||||
<i data-lucide="alert-triangle" class="sum-icon"></i>
|
<div class="step" id="step-2">
|
||||||
<strong id="drv-outdated">0</strong> <span>Outdated</span>
|
<div class="step-num">2</div>
|
||||||
|
<span>Review Drivers</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-item error">
|
<div class="step-line"></div>
|
||||||
<i data-lucide="alert-circle" class="sum-icon"></i>
|
<div class="step" id="step-3">
|
||||||
<strong id="drv-errors">0</strong> <span>Errors</span>
|
<div class="step-num">3</div>
|
||||||
</div>
|
<span>Install Updates</span>
|
||||||
<div class="summary-item muted">
|
|
||||||
<i data-lucide="timer" class="sum-icon"></i>
|
|
||||||
<span id="drv-time">--</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="filter-bar" id="driver-filters" style="display:none">
|
|
||||||
<button class="filter-btn active" data-filter="all"><i data-lucide="list"></i> All</button>
|
|
||||||
<button class="filter-btn" data-filter="outdated"><i data-lucide="alert-triangle"></i> Outdated</button>
|
|
||||||
<button class="filter-btn" data-filter="error"><i data-lucide="x-circle"></i> Errors</button>
|
|
||||||
<button class="filter-btn" data-filter="signed"><i data-lucide="shield-check"></i> Signed</button>
|
|
||||||
</div>
|
|
||||||
<div id="driver-list" class="driver-list">
|
|
||||||
<div class="empty-state">
|
|
||||||
<div class="empty-icon"><i data-lucide="cpu"></i></div>
|
|
||||||
<h3>No Scan Results</h3>
|
|
||||||
<p>Click <strong>Scan Now</strong> to detect installed drivers</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Updates Page -->
|
<!-- ====== DRIVERS TAB ====== -->
|
||||||
<div class="page" id="page-updates">
|
<div class="tab-page" id="tab-drivers">
|
||||||
<div class="page-header">
|
<div class="tab-header">
|
||||||
<div>
|
<div class="tab-header-left">
|
||||||
<h1><i data-lucide="download-cloud" class="page-icon"></i> Windows Update</h1>
|
<h2><i data-lucide="cpu"></i> Installed Drivers</h2>
|
||||||
<p class="subtitle">Keep your system up to date</p>
|
<div class="result-count" id="driver-result-count" style="display:none">
|
||||||
|
<span id="drv-total-2">0</span> found •
|
||||||
|
<span class="warn-text" id="drv-outdated-2">0</span> outdated •
|
||||||
|
scanned in <span id="drv-time-2">--</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<button class="header-btn" onclick="App.scanDrivers()">
|
||||||
<button class="action-btn primary compact" onclick="App.checkUpdates()">
|
<i data-lucide="refresh-cw"></i> Rescan
|
||||||
<i data-lucide="refresh-cw"></i>
|
</button>
|
||||||
<span>Check Now</span>
|
</div>
|
||||||
</button>
|
<div class="filter-strip" id="driver-filter-strip" style="display:none">
|
||||||
|
<button class="pill active" data-filter="all">All</button>
|
||||||
|
<button class="pill" data-filter="outdated"><i data-lucide="alert-triangle"></i> Outdated</button>
|
||||||
|
<button class="pill" data-filter="error"><i data-lucide="x-circle"></i> Errors</button>
|
||||||
|
<button class="pill" data-filter="signed"><i data-lucide="shield-check"></i> Signed</button>
|
||||||
|
</div>
|
||||||
|
<div class="driver-scroll" id="driver-list">
|
||||||
|
<div class="placeholder-msg">
|
||||||
|
<i data-lucide="scan-search"></i>
|
||||||
|
<p>Click <strong>Scan</strong> to detect your drivers</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="update-list" class="update-list">
|
<!-- Update All CTA -->
|
||||||
<div class="empty-state">
|
<div class="cta-bar" id="cta-update-all" style="display:none">
|
||||||
<div class="empty-icon"><i data-lucide="cloud-download"></i></div>
|
<button class="cta-btn" onclick="App.scanDrivers()">
|
||||||
<h3>No Updates Checked</h3>
|
<i data-lucide="download"></i>
|
||||||
<p>Click <strong>Check Now</strong> to search for Windows updates</p>
|
<span>Update All Drivers</span>
|
||||||
|
<span class="cta-count" id="cta-count">0</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ====== UPDATES TAB ====== -->
|
||||||
|
<div class="tab-page" id="tab-updates">
|
||||||
|
<div class="tab-header">
|
||||||
|
<div class="tab-header-left">
|
||||||
|
<h2><i data-lucide="download-cloud"></i> Windows Update</h2>
|
||||||
|
</div>
|
||||||
|
<button class="header-btn" onclick="App.checkUpdates()">
|
||||||
|
<i data-lucide="refresh-cw"></i> Check Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="driver-scroll" id="update-list">
|
||||||
|
<div class="placeholder-msg">
|
||||||
|
<i data-lucide="cloud-download"></i>
|
||||||
|
<p>Click <strong>Check Now</strong> to search for updates</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- System Info Page -->
|
<!-- ====== SYSTEM TAB ====== -->
|
||||||
<div class="page" id="page-system">
|
<div class="tab-page" id="tab-system">
|
||||||
<div class="page-header">
|
<div class="tab-header">
|
||||||
<div>
|
<div class="tab-header-left">
|
||||||
<h1><i data-lucide="monitor" class="page-icon"></i> System Information</h1>
|
<h2><i data-lucide="monitor-cog"></i> System Information</h2>
|
||||||
<p class="subtitle">Detailed hardware and software overview</p>
|
|
||||||
</div>
|
|
||||||
<div class="header-actions">
|
|
||||||
<button class="action-btn primary compact" onclick="App.refreshSysInfo()">
|
|
||||||
<i data-lucide="refresh-cw"></i>
|
|
||||||
<span>Refresh</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button class="header-btn" onclick="App.refreshSysInfo()">
|
||||||
|
<i data-lucide="refresh-cw"></i> Refresh
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="sysinfo-grid" id="sysinfo-grid">
|
<div class="sys-grid">
|
||||||
<div class="info-card glass-panel">
|
<div class="sys-card">
|
||||||
<div class="info-card-header">
|
<div class="sys-card-head"><i data-lucide="laptop"></i> Computer</div>
|
||||||
<i data-lucide="laptop"></i>
|
<div class="sys-row"><span>Name</span><span id="sys-name">--</span></div>
|
||||||
<h4>Computer</h4>
|
<div class="sys-row"><span>OS</span><span id="sys-os">--</span></div>
|
||||||
</div>
|
<div class="sys-row"><span>Version</span><span id="sys-version">--</span></div>
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="tag"></i> Name</span><span class="info-val" id="sys-name">--</span></div>
|
<div class="sys-row"><span>Build</span><span id="sys-build">--</span></div>
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="app-window"></i> OS</span><span class="info-val" id="sys-os">--</span></div>
|
<div class="sys-row"><span>Arch</span><span id="sys-arch">--</span></div>
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="hash"></i> Version</span><span class="info-val" id="sys-version">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="wrench"></i> Build</span><span class="info-val" id="sys-build">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="boxes"></i> Architecture</span><span class="info-val" id="sys-arch">--</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card glass-panel">
|
<div class="sys-card">
|
||||||
<div class="info-card-header">
|
<div class="sys-card-head"><i data-lucide="cpu"></i> Processor</div>
|
||||||
<i data-lucide="cpu"></i>
|
<div class="sys-row"><span>CPU</span><span id="sys-cpu">--</span></div>
|
||||||
<h4>Processor</h4>
|
<div class="sys-row"><span>Cores</span><span id="sys-cores">--</span></div>
|
||||||
</div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="microchip"></i> CPU</span><span class="info-val" id="sys-cpu">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="layers"></i> Cores</span><span class="info-val" id="sys-cores">--</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card glass-panel">
|
<div class="sys-card">
|
||||||
<div class="info-card-header">
|
<div class="sys-card-head"><i data-lucide="memory-stick"></i> Memory</div>
|
||||||
<i data-lucide="memory-stick"></i>
|
<div class="sys-row"><span>Total</span><span id="sys-ram-total">--</span></div>
|
||||||
<h4>Memory</h4>
|
<div class="sys-row"><span>Used</span><span id="sys-ram-used">--</span></div>
|
||||||
|
<div class="sys-row"><span>Free</span><span id="sys-ram-free">--</span></div>
|
||||||
|
<div class="sys-row"><span>Usage</span><span id="sys-ram-pct">--</span></div>
|
||||||
|
<div class="sys-bar-wrap">
|
||||||
|
<div class="sys-bar"><div class="sys-bar-fill ram-bar" id="sys-ram-bar" style="width:0%"></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="database"></i> Total</span><span class="info-val" id="sys-ram-total">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="flame"></i> Used</span><span class="info-val" id="sys-ram-used">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="leaf"></i> Free</span><span class="info-val" id="sys-ram-free">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="percent"></i> Usage</span><span class="info-val" id="sys-ram-pct">--</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card glass-panel">
|
<div class="sys-card">
|
||||||
<div class="info-card-header">
|
<div class="sys-card-head"><i data-lucide="hard-drive"></i> Storage (C:)</div>
|
||||||
<i data-lucide="hard-drive"></i>
|
<div class="sys-row"><span>Total</span><span id="sys-disk-total">--</span></div>
|
||||||
<h4>Storage (C:)</h4>
|
<div class="sys-row"><span>Used</span><span id="sys-disk-used">--</span></div>
|
||||||
|
<div class="sys-row"><span>Free</span><span id="sys-disk-free">--</span></div>
|
||||||
|
<div class="sys-row"><span>Usage</span><span id="sys-disk-pct">--</span></div>
|
||||||
|
<div class="sys-bar-wrap">
|
||||||
|
<div class="sys-bar"><div class="sys-bar-fill disk-bar" id="sys-disk-bar" style="width:0%"></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="database"></i> Total</span><span class="info-val" id="sys-disk-total">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="flame"></i> Used</span><span class="info-val" id="sys-disk-used">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="leaf"></i> Free</span><span class="info-val" id="sys-disk-free">--</span></div>
|
|
||||||
<div class="info-row"><span class="info-key"><i data-lucide="percent"></i> Usage</span><span class="info-val" id="sys-disk-pct">--</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="app-footer">
|
||||||
|
<span>Driver Booster Pro v1.0.0</span>
|
||||||
|
<span class="footer-right">
|
||||||
|
<button class="footer-btn" onclick="App.refreshSysInfo()"><i data-lucide="info"></i> About</button>
|
||||||
|
<button class="footer-btn"><i data-lucide="life-buoy"></i> Help</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading Overlay -->
|
<!-- Loading Overlay -->
|
||||||
@@ -354,7 +269,6 @@
|
|||||||
<i data-lucide="shield-check" class="spinner-icon"></i>
|
<i data-lucide="shield-check" class="spinner-icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<p class="loading-title" id="loading-text">Scanning...</p>
|
<p class="loading-title" id="loading-text">Scanning...</p>
|
||||||
<p class="loading-sub">Please wait while we analyze your system</p>
|
|
||||||
<div class="loading-dots"><span></span><span></span><span></span></div>
|
<div class="loading-dots"><span></span><span></span><span></span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
1353
ui/style.css
1353
ui/style.css
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user