Use PNG icon assets + Windows 11 WinUI3 native design

- Download 27 fluency-style PNG icons (shield, cpu, monitor, wifi, etc.)
- Replace Lucide CDN with embedded PNG <img> tags throughout UI
- Redesign CSS with Windows 11 Mica/Acrylic dark theme:
  - WinUI3 color palette (Segoe UI Variable font)
  - NavigationView-style toolbar tabs with accent indicator bar
  - Subtle borders matching Win11 material layering
  - Accent button style (#0078d4) matching Windows 11 controls
  - Card/surface hierarchy matching WinUI3 specs
- Add IMTAQIN credit in footer with link to https://imtaqin.id
- Fix embed directive for flat icon layout (no subdirectories)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
taqin
2026-04-12 21:06:53 +07:00
parent 83d7a24d1a
commit 4aa4310d7d
30 changed files with 341 additions and 649 deletions

111
ui/app.js
View File

@@ -1,6 +1,5 @@
/* ============================================================
Driver Booster Pro - Application Logic
Driver Navigator Style: tabs, driver rows, action buttons
Driver Booster Pro - PNG Icons Edition
============================================================ */
var App = {
@@ -10,16 +9,9 @@ var App = {
this.setupTabs();
this.setupFilters();
this.refreshSysInfo();
this.refreshIcons();
},
refreshIcons: function() {
if (window.lucide) lucide.createIcons();
},
// ---- Tab Navigation ----
setupTabs: function() {
var self = this;
document.querySelectorAll('.toolbar-tab').forEach(function(tab) {
tab.addEventListener('click', function() {
var id = tab.dataset.tab;
@@ -32,7 +24,6 @@ var App = {
});
},
// ---- Filter Pills ----
setupFilters: function() {
var self = this;
document.querySelectorAll('.pill').forEach(function(btn) {
@@ -54,17 +45,15 @@ var App = {
});
},
// ---- Loading ----
showLoading: function(text) {
document.getElementById('loading-text').textContent = text;
document.getElementById('loading-overlay').style.display = 'flex';
this.refreshIcons();
},
hideLoading: function() {
document.getElementById('loading-overlay').style.display = 'none';
},
// ---- System Info ----
// System Info
refreshSysInfo: function() {
var self = this;
this.showLoading('Collecting system information...');
@@ -72,10 +61,7 @@ var App = {
self.state.sysInfo = info;
self.renderSysInfo(info);
self.hideLoading();
}).catch(function(e) {
console.error(e);
self.hideLoading();
});
}).catch(function(e) { console.error(e); self.hideLoading(); });
},
renderSysInfo: function(d) {
@@ -100,17 +86,15 @@ var App = {
if(db) db.style.width = (d.diskPercent||0)+'%';
},
// ---- Driver Scan ----
// Driver Scan
scanDrivers: function() {
var self = this;
this.showLoading('Scanning drivers... This may take a moment.');
this.showLoading('Scanning drivers...');
// Switch to drivers tab
document.querySelectorAll('.toolbar-tab').forEach(function(t){ t.classList.remove('active'); });
document.querySelector('[data-tab="drivers"]').classList.add('active');
document.querySelectorAll('.tab-page').forEach(function(p){ p.classList.remove('active'); });
document.getElementById('tab-drivers').classList.add('active');
// Update steps
this.setStep(2);
fetch('/api/drivers/scan').then(function(r){ return r.json(); }).then(function(result) {
@@ -118,10 +102,7 @@ var App = {
self.renderDrivers(result);
self.updateScanStats(result);
self.hideLoading();
}).catch(function(e) {
console.error(e);
self.hideLoading();
});
}).catch(function(e) { console.error(e); self.hideLoading(); });
},
updateScanStats: function(r) {
@@ -139,8 +120,7 @@ var App = {
var list = document.getElementById('driver-list');
if (!result.drivers || result.drivers.length === 0) {
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="search-x"></i><p>No drivers found</p></div>';
this.refreshIcons();
list.innerHTML = '<div class="placeholder-msg"><img src="icon-scan.png" class="placeholder-img"><p>No drivers found</p></div>';
return;
}
@@ -150,32 +130,31 @@ var App = {
if (d.needsUpdate) cls.push('outdated');
if (d.status === 'Error' || d.status === 'Degraded') cls.push('error');
var icon = self.driverIcon(d.deviceClass);
var iconFile = self.driverIconFile(d.deviceClass);
var barClass = d.needsUpdate ? 'warn' : (d.status === 'Error' ? 'err' : 'ok');
var signBadge = d.isSigned
? '<span class="drv-badge signed"><i data-lucide="shield-check"></i> Signed</span>'
: '<span class="drv-badge unsigned"><i data-lucide="shield-x"></i></span>';
? '<span class="drv-badge signed"><img src="icon-shield.png" class="drv-badge-img" style="width:10px;height:10px"> Signed</span>'
: '<span class="drv-badge unsigned">Unsigned</span>';
var actionBtn = d.needsUpdate
? '<button class="drv-btn install-btn"><i data-lucide="download"></i> Download</button>' +
'<button class="drv-btn"><i data-lucide="play"></i> Install</button>'
: '<button class="drv-btn installed-btn"><i data-lucide="circle-check"></i> Up to date</button>';
? '<button class="drv-btn install-btn"><img src="icon-download.png" style="width:13px;height:13px"> Download</button>' +
'<button class="drv-btn"><img src="icon-install.png" style="width:13px;height:13px"> Install</button>'
: '<button class="drv-btn ok-btn"><img src="icon-checkmark.png" style="width:13px;height:13px"> Up to date</button>';
return '<div class="' + cls.join(' ') + '" data-signed="' + d.isSigned + '">' +
'<div class="drv-icon"><i data-lucide="' + icon + '"></i></div>' +
'<div class="drv-icon"><img src="icon-' + iconFile + '" class="drv-icon-img"></div>' +
'<div class="drv-info">' +
'<div class="drv-name">' + self.esc(d.deviceName) + '</div>' +
'<div class="drv-meta">' + self.esc(d.manufacturer||'Unknown') + ' &middot; v' + self.esc(d.driverVersion||'?') + ' &middot; ' + self.esc(d.driverDate) + ' ' + signBadge + '</div>' +
'</div>' +
'<div class="drv-progress">' +
'<div class="drv-bar"><div class="drv-bar-fill ' + barClass + '"></div></div>' +
'<div class="drv-meta">' + self.esc(d.manufacturer||'Unknown') +
' &middot; v' + self.esc(d.driverVersion||'?') +
' &middot; ' + self.esc(d.driverDate) + ' ' + signBadge + '</div>' +
'</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>';
}).join('');
// Show CTA if there are outdated drivers
var cta = document.getElementById('cta-update-all');
if (result.outdatedCount > 0) {
cta.style.display = 'flex';
@@ -183,30 +162,27 @@ var App = {
} else {
cta.style.display = 'none';
}
this.refreshIcons();
},
driverIcon: function(cls) {
if (!cls) return 'package';
driverIconFile: function(cls) {
if (!cls) return 'package.png';
var u = cls.toUpperCase();
var m = {
'DISPLAY':'monitor','MEDIA':'volume-2','AUDIO':'volume-2','SOUND':'volume-2',
'NET':'wifi','NETWORK':'wifi','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','FIRMWARE':'circuit-board','SECURITY':'shield',
'SENSOR':'thermometer'
'DISPLAY':'monitor.png','MEDIA':'speaker.png','AUDIO':'speaker.png','SOUND':'speaker.png',
'NET':'wifi.png','NETWORK':'wifi.png','USB':'usb.png','HID':'mouse.png',
'KEYBOARD':'keyboard.png','DISK':'harddrive.png','STORAGE':'harddrive.png',
'PROCESSOR':'cpu.png','SYSTEM':'settings.png','BLUETOOTH':'bluetooth.png',
'CAMERA':'camera.png','IMAGE':'camera.png','PRINT':'printer.png',
'BATTERY':'battery.png'
};
for (var k in m) { if (u.indexOf(k) !== -1) return m[k]; }
return 'package';
return 'package.png';
},
// ---- Windows Update ----
// Windows Update
checkUpdates: function() {
var self = this;
this.showLoading('Checking for Windows updates...');
// Switch to updates tab
document.querySelectorAll('.toolbar-tab').forEach(function(t){ t.classList.remove('active'); });
document.querySelector('[data-tab="updates"]').classList.add('active');
document.querySelectorAll('.tab-page').forEach(function(p){ p.classList.remove('active'); });
@@ -216,24 +192,18 @@ var App = {
self.state.updates = result;
self.renderUpdates(result);
self.hideLoading();
}).catch(function(e) {
console.error(e);
self.hideLoading();
});
}).catch(function(e) { console.error(e); self.hideLoading(); });
},
renderUpdates: function(result) {
var list = document.getElementById('update-list');
if (result.error) {
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="alert-circle"></i><p style="color:var(--red)">' + this.esc(result.error) + '</p></div>';
this.refreshIcons();
list.innerHTML = '<div class="placeholder-msg"><img src="icon-error.png" class="placeholder-img"><p style="color:var(--red)">' + this.esc(result.error) + '</p></div>';
return;
}
if (!result.updates || result.updates.length === 0) {
list.innerHTML = '<div class="placeholder-msg"><i data-lucide="circle-check"></i><p>Your system is fully up to date!</p></div>';
this.refreshIcons();
list.innerHTML = '<div class="placeholder-msg"><img src="icon-checkmark.png" class="placeholder-img"><p>Your system is fully up to date!</p></div>';
return;
}
@@ -243,32 +213,28 @@ var App = {
var html = '';
if (pending.length > 0) {
html += '<div class="upd-section pend"><i data-lucide="download"></i> Pending (' + pending.length + ')</div>';
html += '<div class="upd-section pend"><img src="icon-download.png" style="width:16px;height:16px"> Pending (' + pending.length + ')</div>';
html += pending.map(function(u) {
return '<div class="upd-row pending">' +
'<div class="upd-title">' + self.esc(u.title) + '</div>' +
'<div class="upd-meta">' +
(u.kbArticle ? '<span class="upd-tag"><i data-lucide="file-text"></i> '+self.esc(u.kbArticle)+'</span>' : '') +
(u.category ? '<span class="upd-tag"><i data-lucide="folder"></i> '+self.esc(u.category)+'</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="upd-tag"><i data-lucide="alert-triangle"></i> '+self.esc(u.severity)+'</span>' : '') +
'</div>' +
'</div>';
(u.kbArticle ? '<span class="upd-tag"><img src="icon-info.png" style="width:12px;height:12px"> '+self.esc(u.kbArticle)+'</span>' : '') +
(u.category ? '<span class="upd-tag"><img src="icon-package.png" style="width:12px;height:12px"> '+self.esc(u.category)+'</span>' : '') +
(u.size ? '<span class="upd-tag"><img src="icon-harddrive.png" style="width:12px;height:12px"> '+self.esc(u.size)+'</span>' : '') +
(u.severity && u.severity !== 'Unspecified' ? '<span class="upd-tag"><img src="icon-warning.png" style="width:12px;height:12px"> '+self.esc(u.severity)+'</span>' : '') +
'</div></div>';
}).join('');
}
if (installed.length > 0) {
html += '<div class="upd-section inst"><i data-lucide="check-circle"></i> Recently Installed (' + installed.length + ')</div>';
html += '<div class="upd-section inst"><img src="icon-checkmark.png" style="width:16px;height:16px"> Recently Installed (' + installed.length + ')</div>';
html += installed.map(function(u) {
return '<div class="upd-row done"><div class="upd-title">' + self.esc(u.title) + '</div></div>';
}).join('');
}
list.innerHTML = html;
this.refreshIcons();
},
// ---- Step bar ----
setStep: function(n) {
for (var i = 1; i <= 3; i++) {
var el = document.getElementById('step-' + i);
@@ -279,7 +245,6 @@ var App = {
}
},
// ---- Helpers ----
set: function(id, val) {
var el = document.getElementById(id);
if (el) el.textContent = (val != null && val !== '') ? val : '--';

BIN
ui/icon-battery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

BIN
ui/icon-bluetooth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
ui/icon-camera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
ui/icon-checkmark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

BIN
ui/icon-cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

BIN
ui/icon-cpu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

BIN
ui/icon-download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

BIN
ui/icon-error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ui/icon-harddrive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ui/icon-help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
ui/icon-info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ui/icon-install.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
ui/icon-keyboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

BIN
ui/icon-laptop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
ui/icon-monitor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ui/icon-mouse.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ui/icon-package.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

BIN
ui/icon-printer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

BIN
ui/icon-ram.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
ui/icon-refresh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

BIN
ui/icon-scan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

BIN
ui/icon-settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
ui/icon-shield.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
ui/icon-speaker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
ui/icon-usb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
ui/icon-warning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

BIN
ui/icon-wifi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -5,23 +5,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Driver Booster Pro</title>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
</head>
<body>
<div class="app">
<!-- Title Bar -->
<div class="titlebar">
<div class="titlebar-left">
<div class="app-logo">
<i data-lucide="shield-check"></i>
</div>
<img src="icon-shield.png" class="app-logo-img" alt="">
<div class="app-title">
<span class="app-name">DRIVER BOOSTER</span>
<span class="app-edition">PRO</span>
</div>
</div>
<div class="titlebar-right">
<div class="sys-status" id="sys-status">
<div class="sys-status">
<div class="status-led"></div>
<span>System Protected</span>
</div>
@@ -31,27 +28,19 @@
<!-- Toolbar Tabs -->
<div class="toolbar">
<button class="toolbar-tab active" data-tab="scan">
<div class="tab-icon-wrap scan-icon-wrap">
<i data-lucide="scan-search"></i>
</div>
<img src="icon-scan.png" class="tab-img" alt="">
<span>Scan</span>
</button>
<button class="toolbar-tab" data-tab="drivers">
<div class="tab-icon-wrap drivers-icon-wrap">
<i data-lucide="cpu"></i>
</div>
<img src="icon-cpu.png" class="tab-img" alt="">
<span>Drivers</span>
</button>
<button class="toolbar-tab" data-tab="updates">
<div class="tab-icon-wrap updates-icon-wrap">
<i data-lucide="download-cloud"></i>
</div>
<img src="icon-download.png" class="tab-img" alt="">
<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>
<img src="icon-settings.png" class="tab-img" alt="">
<span>System</span>
</button>
</div>
@@ -63,72 +52,35 @@
<div class="tab-page active" id="tab-scan">
<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>
<img src="icon-monitor.png" class="hero-img" alt="">
<img src="icon-shield.png" class="hero-shield" alt="">
</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="scan-stats">
<div class="mini-stat">
<i data-lucide="cpu"></i>
<img src="icon-cpu.png" class="mini-icon" alt="">
<span id="scan-stat-total">--</span>
<label>Drivers</label>
</div>
<div class="mini-stat warn">
<i data-lucide="alert-triangle"></i>
<img src="icon-warning.png" class="mini-icon" alt="">
<span id="scan-stat-outdated">--</span>
<label>Outdated</label>
</div>
<div class="mini-stat danger">
<i data-lucide="x-circle"></i>
<img src="icon-error.png" class="mini-icon" alt="">
<span id="scan-stat-errors">--</span>
<label>Errors</label>
</div>
</div>
<button class="big-scan-btn" id="btn-scan" onclick="App.scanDrivers()">
<i data-lucide="scan-search"></i>
<button class="big-scan-btn" onclick="App.scanDrivers()">
<img src="icon-scan.png" class="btn-icon" alt="">
<span>SCAN NOW</span>
</button>
</div>
</div>
<!-- Step Indicator -->
<div class="step-bar">
<div class="step active" id="step-1">
@@ -152,7 +104,7 @@
<div class="tab-page" id="tab-drivers">
<div class="tab-header">
<div class="tab-header-left">
<h2><i data-lucide="cpu"></i> Installed Drivers</h2>
<h2><img src="icon-cpu.png" class="h2-icon" alt=""> Installed Drivers</h2>
<div class="result-count" id="driver-result-count" style="display:none">
<span id="drv-total-2">0</span> found &bull;
<span class="warn-text" id="drv-outdated-2">0</span> outdated &bull;
@@ -160,25 +112,25 @@
</div>
</div>
<button class="header-btn" onclick="App.scanDrivers()">
<i data-lucide="refresh-cw"></i> Rescan
<img src="icon-refresh.png" class="hdr-icon" alt=""> Rescan
</button>
</div>
<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>
<button class="pill" data-filter="outdated"><img src="icon-warning.png" class="pill-icon" alt=""> Outdated</button>
<button class="pill" data-filter="error"><img src="icon-error.png" class="pill-icon" alt=""> Errors</button>
<button class="pill" data-filter="signed"><img src="icon-shield.png" class="pill-icon" alt=""> Signed</button>
</div>
<div class="driver-scroll" id="driver-list">
<div class="placeholder-msg">
<i data-lucide="scan-search"></i>
<img src="icon-scan.png" class="placeholder-img" alt="">
<p>Click <strong>Scan</strong> to detect your drivers</p>
</div>
</div>
<!-- Update All CTA -->
<div class="cta-bar" id="cta-update-all" style="display:none">
<button class="cta-btn" onclick="App.scanDrivers()">
<i data-lucide="download"></i>
<img src="icon-install.png" class="cta-icon" alt="">
<span>Update All Drivers</span>
<span class="cta-count" id="cta-count">0</span>
</button>
@@ -189,15 +141,15 @@
<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>
<h2><img src="icon-cloud.png" class="h2-icon" alt=""> Windows Update</h2>
</div>
<button class="header-btn" onclick="App.checkUpdates()">
<i data-lucide="refresh-cw"></i> Check Now
<img src="icon-refresh.png" class="hdr-icon" alt=""> Check Now
</button>
</div>
<div class="driver-scroll" id="update-list">
<div class="placeholder-msg">
<i data-lucide="cloud-download"></i>
<img src="icon-cloud.png" class="placeholder-img" alt="">
<p>Click <strong>Check Now</strong> to search for updates</p>
</div>
</div>
@@ -207,15 +159,15 @@
<div class="tab-page" id="tab-system">
<div class="tab-header">
<div class="tab-header-left">
<h2><i data-lucide="monitor-cog"></i> System Information</h2>
<h2><img src="icon-settings.png" class="h2-icon" alt=""> System Information</h2>
</div>
<button class="header-btn" onclick="App.refreshSysInfo()">
<i data-lucide="refresh-cw"></i> Refresh
<img src="icon-refresh.png" class="hdr-icon" alt=""> Refresh
</button>
</div>
<div class="sys-grid">
<div class="sys-card">
<div class="sys-card-head"><i data-lucide="laptop"></i> Computer</div>
<div class="sys-card-head"><img src="icon-laptop.png" class="sys-head-icon" alt=""> Computer</div>
<div class="sys-row"><span>Name</span><span id="sys-name">--</span></div>
<div class="sys-row"><span>OS</span><span id="sys-os">--</span></div>
<div class="sys-row"><span>Version</span><span id="sys-version">--</span></div>
@@ -223,12 +175,12 @@
<div class="sys-row"><span>Arch</span><span id="sys-arch">--</span></div>
</div>
<div class="sys-card">
<div class="sys-card-head"><i data-lucide="cpu"></i> Processor</div>
<div class="sys-card-head"><img src="icon-cpu.png" class="sys-head-icon" alt=""> Processor</div>
<div class="sys-row"><span>CPU</span><span id="sys-cpu">--</span></div>
<div class="sys-row"><span>Cores</span><span id="sys-cores">--</span></div>
</div>
<div class="sys-card">
<div class="sys-card-head"><i data-lucide="memory-stick"></i> Memory</div>
<div class="sys-card-head"><img src="icon-ram.png" class="sys-head-icon" alt=""> Memory</div>
<div class="sys-row"><span>Total</span><span id="sys-ram-total">--</span></div>
<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>
@@ -238,7 +190,7 @@
</div>
</div>
<div class="sys-card">
<div class="sys-card-head"><i data-lucide="hard-drive"></i> Storage (C:)</div>
<div class="sys-card-head"><img src="icon-harddrive.png" class="sys-head-icon" alt=""> Storage (C:)</div>
<div class="sys-row"><span>Total</span><span id="sys-disk-total">--</span></div>
<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>
@@ -253,10 +205,10 @@
<!-- Footer -->
<div class="app-footer">
<span>Driver Booster Pro v1.0.0</span>
<span>Driver Booster Pro v1.0.0 &mdash; Made by <a href="https://imtaqin.id" class="credit-link" target="_blank">IMTAQIN</a></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>
<button class="footer-btn" onclick="App.refreshSysInfo()"><img src="icon-info.png" class="footer-icon" alt=""> About</button>
<button class="footer-btn"><img src="icon-help.png" class="footer-icon" alt=""> Help</button>
</span>
</div>
</div>
@@ -266,7 +218,7 @@
<div class="loading-card">
<div class="loading-spinner">
<div class="spinner-ring"></div>
<i data-lucide="shield-check" class="spinner-icon"></i>
<img src="icon-shield.png" class="spinner-img" alt="">
</div>
<p class="loading-title" id="loading-text">Scanning...</p>
<div class="loading-dots"><span></span><span></span><span></span></div>

View File

@@ -1,613 +1,388 @@
/* ============================================================
Driver Booster Pro - Driver Navigator Style
Toolbar tabs + driver list + Download/Install buttons
Driver Booster Pro - Windows 11 WinUI3 + PNG Icons
Mica/Acrylic materials, rounded corners, native look
============================================================ */
:root {
--bg: linear-gradient(180deg, #0a1628 0%, #0f1d32 50%, #0a1628 100%);
--surface: #111d33;
--surface-light: #162442;
--surface-hover: #1a2d50;
--border: rgba(255,255,255,0.07);
--border-accent: rgba(59,130,246,0.3);
/* Windows 11 Dark Mica palette */
--bg: #202020;
--mica: #2c2c2c;
--surface: #2d2d2d;
--surface-light: #383838;
--surface-hover: #3a3a3a;
--card: #323232;
--border: rgba(255,255,255,0.0578);
--border-light: rgba(255,255,255,0.0837);
--border-top: rgba(255,255,255,0.093);
--text: #e8edf5;
--text-sec: #8899b4;
--text-dim: #56687e;
--text: #ffffffde;
--text-sec: #ffffffa0;
--text-dim: #ffffff60;
--accent: #3b82f6;
--accent-light: #60a5fa;
--accent-dark: #2563eb;
--accent-glow: rgba(59,130,246,0.25);
/* Windows 11 accent (Blue) */
--accent: #60cdff;
--accent-bg: #0078d4;
--accent-hover: #429ce3;
--accent-press: #005a9e;
--accent-subtle: rgba(96,205,255,0.08);
--green: #10b981;
--green-bg: rgba(16,185,129,0.12);
--yellow: #f59e0b;
--yellow-bg: rgba(245,158,11,0.12);
--red: #ef4444;
--red-bg: rgba(239,68,68,0.12);
--cyan: #06b6d4;
--green: #6ccb5f;
--green-bg: rgba(108,203,95,0.1);
--yellow: #fce100;
--yellow-bg: rgba(252,225,0,0.1);
--red: #ff99a4;
--red-bg: rgba(255,153,164,0.1);
--r: 10px;
--r-sm: 6px;
--radius: 8px;
--radius-lg: 12px;
--radius-sm: 4px;
}
* { margin:0; padding:0; box-sizing:border-box; }
*{margin:0;padding:0;box-sizing:border-box}
body {
font-family: 'Segoe UI Variable','Segoe UI',-apple-system,BlinkMacSystemFont,sans-serif;
background: var(--bg);
background-attachment: fixed;
color: var(--text);
height: 100vh;
overflow: hidden;
-webkit-font-smoothing: antialiased;
font-family:'Segoe UI Variable Display','Segoe UI Variable','Segoe UI',-apple-system,sans-serif;
background:var(--bg);
color:var(--text);
height:100vh;overflow:hidden;
font-size:14px;
-webkit-font-smoothing:antialiased;
}
/* ---- Shared icon sizes ---- */
.app-logo-img { width:24px; height:24px; }
.tab-img { width:32px; height:32px; }
.h2-icon { width:20px; height:20px; vertical-align:middle; margin-right:6px; }
.hdr-icon { width:14px; height:14px; vertical-align:middle; }
.pill-icon { width:12px; height:12px; vertical-align:middle; }
.mini-icon { width:20px; height:20px; }
.btn-icon { width:20px; height:20px; }
.placeholder-img { width:48px; height:48px; opacity:.35; }
.sys-head-icon { width:16px; height:16px; vertical-align:middle; }
.footer-icon { width:12px; height:12px; vertical-align:middle; }
.cta-icon { width:20px; height:20px; }
.drv-icon-img { width:24px; height:24px; }
.spinner-img { width:24px; height:24px; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); }
/* ---- App Shell ---- */
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
.app { display:flex; flex-direction:column; height:100vh; background:var(--mica); }
/* ---- Title Bar ---- */
/* ---- Title Bar (Win11 style) ---- */
.titlebar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 24px 10px;
border-bottom: 1px solid var(--border);
background: rgba(10,22,40,0.8);
backdrop-filter: blur(12px);
flex-shrink: 0;
}
.titlebar-left { display:flex; align-items:center; gap:12px; }
.app-logo {
width: 36px; height: 36px;
background: linear-gradient(135deg, var(--accent), var(--cyan));
border-radius: 10px;
display: flex; align-items:center; justify-content:center;
box-shadow: 0 2px 12px var(--accent-glow);
}
.app-logo svg { width:20px; height:20px; color:white; }
.app-title { display:flex; align-items:baseline; gap:6px; }
.app-name {
font-size: 18px; font-weight: 800;
letter-spacing: 2px;
background: linear-gradient(90deg, #fff, #94a3b8);
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
display:flex; justify-content:space-between; align-items:center;
padding:10px 16px;
background:var(--bg);
border-bottom:1px solid var(--border);
flex-shrink:0;
-webkit-app-region:drag;
}
.titlebar-left { display:flex; align-items:center; gap:10px; -webkit-app-region:no-drag; }
.app-title { display:flex; align-items:center; gap:8px; }
.app-name { font-size:13px; font-weight:600; color:var(--text); letter-spacing:.3px; }
.app-edition {
font-size: 11px; font-weight: 700;
color: var(--cyan);
background: rgba(6,182,212,0.15);
padding: 2px 8px; border-radius: 4px;
letter-spacing: 1px;
}
.sys-status {
display:flex; align-items:center; gap:6px;
font-size: 12px; color: var(--text-sec);
font-size:10px; font-weight:600; color:var(--accent);
background:var(--accent-subtle); padding:1px 6px;
border-radius:var(--radius-sm); letter-spacing:.5px;
}
.sys-status { display:flex; align-items:center; gap:6px; font-size:12px; color:var(--text-sec); }
.status-led {
width:8px; height:8px; border-radius:50%;
background: var(--green);
box-shadow: 0 0 8px var(--green);
animation: pulse 2s ease-in-out infinite;
background:var(--green); box-shadow:0 0 6px var(--green);
animation:pulse 2.5s ease-in-out infinite;
}
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
/* ---- Toolbar ---- */
/* ---- Toolbar (Win11 Tabs / NavigationView) ---- */
.toolbar {
display: flex;
gap: 4px;
padding: 12px 24px;
border-bottom: 1px solid var(--border);
background: rgba(10,22,40,0.5);
flex-shrink: 0;
display:flex; gap:2px; padding:6px 12px;
background:var(--mica);
border-bottom:1px solid var(--border);
flex-shrink:0;
}
.toolbar-tab {
display: flex; flex-direction: column;
align-items: center; gap: 6px;
padding: 12px 28px;
border: 1px solid transparent;
border-radius: var(--r);
background: transparent;
color: var(--text-sec);
font-size: 11.5px; font-weight: 600;
letter-spacing: 0.5px;
text-transform: uppercase;
cursor: pointer;
transition: all .2s ease;
font-family: inherit;
position: relative;
display:flex; flex-direction:column; align-items:center; gap:4px;
padding:8px 20px;
border:none; border-radius:var(--radius);
background:transparent; color:var(--text-sec);
font-size:11px; font-weight:500;
cursor:pointer; transition:all .15s ease; font-family:inherit;
position:relative;
}
.toolbar-tab:hover { background: var(--surface); color: var(--text); }
.toolbar-tab:hover { background:var(--surface-hover); color:var(--text); }
.toolbar-tab.active {
background: linear-gradient(180deg, var(--surface-light), var(--surface));
border-color: var(--border-accent);
color: var(--accent-light);
box-shadow: 0 2px 12px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.05);
background:var(--surface);
color:var(--text);
border:1px solid var(--border-light);
border-top:1px solid var(--border-top);
}
.toolbar-tab.active::after {
content:'';
position:absolute; bottom:4px; left:50%; transform:translateX(-50%);
width:16px; height:3px; border-radius:2px;
background:var(--accent);
}
.tab-icon-wrap {
width: 44px; height: 44px;
border-radius: 12px;
display: flex; align-items:center; justify-content:center;
transition: all .2s ease;
}
.tab-icon-wrap svg { width: 22px; height: 22px; }
.scan-icon-wrap { background: rgba(59,130,246,0.1); color: var(--accent); }
.drivers-icon-wrap { background: rgba(6,182,212,0.1); color: var(--cyan); }
.updates-icon-wrap { background: rgba(16,185,129,0.1); color: var(--green); }
.settings-icon-wrap { background: rgba(245,158,11,0.1); color: var(--yellow); }
.toolbar-tab.active .scan-icon-wrap { background: rgba(59,130,246,0.2); }
.toolbar-tab.active .drivers-icon-wrap { background: rgba(6,182,212,0.2); }
.toolbar-tab.active .updates-icon-wrap { background: rgba(16,185,129,0.2); }
.toolbar-tab.active .settings-icon-wrap { background: rgba(245,158,11,0.2); }
/* ---- Content Area ---- */
.content-area {
flex: 1;
overflow: hidden;
position: relative;
}
.tab-page {
display: none;
height: 100%;
animation: fadeUp .3s ease;
}
.tab-page.active { display: flex; flex-direction: column; }
@keyframes fadeUp {
from { opacity:0; transform:translateY(8px); }
to { opacity:1; transform:translateY(0); }
}
/* ---- Content ---- */
.content-area { flex:1; overflow:hidden; position:relative; }
.tab-page { display:none; height:100%; animation:fadeUp .25s ease; }
.tab-page.active { display:flex; flex-direction:column; }
@keyframes fadeUp{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
/* ---- Scan Hero ---- */
.scan-hero {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 60px;
padding: 40px;
flex:1; display:flex; align-items:center; justify-content:center;
gap:48px; padding:32px;
}
.scan-illustration { flex-shrink:0; }
.computer-svg { width: 220px; height: 200px; }
.scan-info { max-width: 380px; }
.scan-info h2 { font-size: 28px; font-weight: 800; margin-bottom: 10px; letter-spacing:-0.5px; }
.scan-info p { color: var(--text-sec); font-size: 14px; line-height: 1.6; margin-bottom: 24px; }
.scan-stats {
display: flex; gap: 20px;
margin-bottom: 28px;
.scan-illustration { position:relative; flex-shrink:0; }
.hero-img { width:120px; height:120px; filter:drop-shadow(0 4px 16px rgba(0,0,0,0.3)); }
.hero-shield {
width:48px; height:48px; position:absolute; bottom:-6px; right:-12px;
filter:drop-shadow(0 2px 8px rgba(108,203,95,0.4));
animation:shieldBob 3s ease-in-out infinite;
}
@keyframes shieldBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-5px)}}
.scan-info { max-width:360px; }
.scan-info h2 { font-size:28px; font-weight:600; margin-bottom:8px; }
.scan-info p { color:var(--text-sec); font-size:14px; line-height:1.5; margin-bottom:20px; }
.scan-stats { display:flex; gap:10px; margin-bottom:24px; }
.mini-stat {
display: flex; align-items:center; gap: 8px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r);
padding: 10px 16px;
display:flex; align-items:center; gap:8px;
background:var(--surface); border:1px solid var(--border);
border-radius:var(--radius); padding:10px 14px;
}
.mini-stat svg { width:16px; height:16px; color: var(--accent-light); }
.mini-stat span { font-size:20px; font-weight:700; }
.mini-stat label { font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.5px; }
.mini-stat.warn svg { color: var(--yellow); }
.mini-stat.warn span { color: var(--yellow); }
.mini-stat.danger svg { color: var(--red); }
.mini-stat.danger span { color: var(--red); }
.mini-stat span { font-size:18px; font-weight:700; }
.mini-stat label { font-size:10px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.4px; }
.mini-stat.warn span { color:var(--yellow); }
.mini-stat.danger span { color:var(--red); }
/* Win11 accent button */
.big-scan-btn {
display: flex; align-items:center; gap:12px;
padding: 16px 48px;
background: linear-gradient(135deg, var(--accent-dark), var(--accent));
border: none; border-radius: 12px;
color: white; font-size: 16px; font-weight: 700;
letter-spacing: 2px;
cursor: pointer;
transition: all .25s ease;
font-family: inherit;
box-shadow: 0 4px 20px var(--accent-glow);
display:flex; align-items:center; gap:10px;
padding:12px 40px;
background:var(--accent-bg); border:none;
border-radius:var(--radius); color:white;
font-size:14px; font-weight:600;
cursor:pointer; transition:all .15s ease; font-family:inherit;
}
.big-scan-btn svg { width:22px; height:22px; }
.big-scan-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 30px rgba(59,130,246,0.4);
}
.big-scan-btn:active { transform:translateY(0); }
.big-scan-btn:hover { background:var(--accent-hover); }
.big-scan-btn:active { background:var(--accent-press); transform:scale(0.98); }
/* ---- Step Bar ---- */
.step-bar {
display: flex; align-items:center; justify-content:center;
gap: 0;
padding: 18px 24px;
border-top: 1px solid var(--border);
background: rgba(10,22,40,0.5);
flex-shrink: 0;
}
.step {
display:flex; align-items:center; gap:8px;
font-size: 12px; color: var(--text-dim);
font-weight: 500;
}
.step.active { color: var(--accent-light); }
.step.done { color: var(--green); }
.step-num {
width:24px; height:24px;
border-radius:50%;
border: 2px solid var(--text-dim);
display:flex; align-items:center; justify-content:center;
font-size: 11px; font-weight:700;
padding:12px 16px;
border-top:1px solid var(--border); background:var(--bg);
flex-shrink:0;
}
.step.active .step-num { border-color: var(--accent); background: var(--accent); color:white; }
.step.done .step-num { border-color: var(--green); background: var(--green); color:white; }
.step-line {
width: 60px; height: 2px;
background: var(--text-dim);
margin: 0 12px;
opacity: 0.3;
.step { display:flex; align-items:center; gap:6px; font-size:12px; color:var(--text-dim); font-weight:500; }
.step.active { color:var(--accent); }
.step.done { color:var(--green); }
.step-num {
width:22px; height:22px; border-radius:50%;
border:2px solid var(--text-dim);
display:flex; align-items:center; justify-content:center;
font-size:11px; font-weight:600;
}
.step.active .step-num { border-color:var(--accent-bg); background:var(--accent-bg); color:white; }
.step.done .step-num { border-color:var(--green); background:var(--green); color:#000; }
.step-line { width:48px; height:1px; background:var(--text-dim); margin:0 10px; opacity:.3; }
/* ---- Tab Headers ---- */
/* ---- Tab Header ---- */
.tab-header {
display: flex; justify-content:space-between; align-items:center;
padding: 18px 24px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
display:flex; justify-content:space-between; align-items:center;
padding:14px 20px; border-bottom:1px solid var(--border); flex-shrink:0;
}
.tab-header-left h2 {
font-size: 16px; font-weight: 700;
display:flex; align-items:center; gap:8px;
}
.tab-header-left h2 svg { width:20px; height:20px; color:var(--accent-light); }
.result-count { font-size:12px; color:var(--text-dim); margin-top:3px; }
.warn-text { color: var(--yellow); }
.tab-header-left h2 { font-size:16px; font-weight:600; display:flex; align-items:center; }
.result-count { font-size:12px; color:var(--text-dim); margin-top:2px; }
.warn-text { color:var(--yellow); }
/* Win11 subtle button */
.header-btn {
display:flex; align-items:center; gap:6px;
padding: 8px 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-sm);
color: var(--text-sec);
font-size: 12.5px; font-weight:600;
cursor:pointer;
transition: all .2s ease;
font-family: inherit;
}
.header-btn svg { width:14px; height:14px; }
.header-btn:hover { border-color: var(--accent); color: var(--accent-light); background: var(--surface-light); }
/* ---- Filter Strip ---- */
.filter-strip {
display:flex; gap:6px;
padding: 12px 24px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.pill {
display:flex; align-items:center; gap:5px;
padding: 5px 14px;
border:1px solid var(--border);
border-radius:20px;
background:transparent;
color: var(--text-dim);
font-size:12px; font-weight:500;
cursor:pointer;
transition: all .15s ease;
font-family:inherit;
padding:6px 14px; background:var(--surface);
border:1px solid var(--border); border-radius:var(--radius);
color:var(--text-sec); font-size:12px; font-weight:500;
cursor:pointer; transition:all .15s ease; font-family:inherit;
}
.pill svg { width:12px; height:12px; }
.pill:hover { border-color: var(--accent); color: var(--accent-light); }
.pill.active { background:var(--accent); border-color:var(--accent); color:white; }
.header-btn:hover { background:var(--surface-hover); color:var(--text); }
/* ---- Driver Scroll List ---- */
.driver-scroll {
flex: 1;
overflow-y: auto;
padding: 12px 24px;
/* ---- Filter ---- */
.filter-strip { display:flex; gap:4px; padding:8px 20px; border-bottom:1px solid var(--border); flex-shrink:0; }
.pill {
display:flex; align-items:center; gap:4px;
padding:4px 12px; border:1px solid var(--border); border-radius:var(--radius);
background:transparent; color:var(--text-dim);
font-size:12px; font-weight:500; cursor:pointer;
transition:all .12s ease; font-family:inherit;
}
.driver-scroll::-webkit-scrollbar { width:5px; }
.driver-scroll::-webkit-scrollbar-track { background:transparent; }
.driver-scroll::-webkit-scrollbar-thumb { background:var(--border); border-radius:3px; }
.pill:hover { background:var(--surface-hover); color:var(--text); }
.pill.active { background:var(--accent-bg); border-color:var(--accent-bg); color:white; }
/* Placeholder */
.placeholder-msg {
text-align:center;
padding: 80px 20px;
color: var(--text-dim);
}
.placeholder-msg svg { width:48px; height:48px; margin-bottom:12px; opacity:.3; }
.placeholder-msg p { font-size:14px; }
/* ---- Driver Scroll ---- */
.driver-scroll { flex:1; overflow-y:auto; padding:8px 20px; }
.driver-scroll::-webkit-scrollbar{width:6px}
.driver-scroll::-webkit-scrollbar-track{background:transparent}
.driver-scroll::-webkit-scrollbar-thumb{background:rgba(255,255,255,0.1);border-radius:3px}
.driver-scroll::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,0.15)}
/* ---- Driver Row (like Driver Navigator) ---- */
.placeholder-msg { text-align:center; padding:64px 20px; color:var(--text-dim); }
.placeholder-msg p { font-size:14px; margin-top:8px; }
/* ---- Driver Row (WinUI3 ListItem) ---- */
.drv-row {
display: flex;
align-items: center;
gap: 14px;
padding: 14px 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r);
margin-bottom: 8px;
transition: all .2s ease;
display:flex; align-items:center; gap:12px;
padding:10px 14px;
background:var(--card); border:1px solid var(--border);
border-radius:var(--radius); margin-bottom:4px;
transition:background .12s ease;
}
.drv-row:hover { border-color: rgba(59,130,246,0.2); background: var(--surface-hover); }
.drv-row.outdated { border-left: 3px solid var(--yellow); }
.drv-row.error { border-left: 3px solid var(--red); }
.drv-row:hover { background:var(--surface-hover); }
.drv-row.outdated { border-left:3px solid var(--yellow); }
.drv-row.error { border-left:3px solid var(--red); }
.drv-icon {
width:40px; height:40px;
border-radius: 10px;
display:flex; align-items:center; justify-content:center;
flex-shrink:0;
background: rgba(59,130,246,0.1);
color: var(--accent-light);
width:36px; height:36px; border-radius:var(--radius);
display:flex; align-items:center; justify-content:center; flex-shrink:0;
background:var(--accent-subtle);
}
.drv-icon svg { width:20px; height:20px; }
.drv-info { flex:1; min-width:0; }
.drv-name {
font-size: 13.5px; font-weight:600;
white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.drv-meta { font-size:11.5px; color:var(--text-dim); margin-top:2px; }
.drv-name { font-size:13px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.drv-meta { font-size:11px; color:var(--text-dim); margin-top:1px; display:flex; align-items:center; gap:4px; flex-wrap:wrap; }
/* Progress bar per driver */
.drv-progress {
width: 120px;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 3px;
}
.drv-bar {
height:4px;
background: rgba(255,255,255,0.05);
border-radius:2px;
overflow:hidden;
}
.drv-bar-fill {
height:100%;
border-radius:2px;
transition: width .6s ease;
}
.drv-bar-fill.ok { background: var(--green); width:100%; }
.drv-bar-fill.warn { background: var(--yellow); width:60%; }
.drv-bar-fill.err { background: var(--red); width:30%; }
.drv-size { font-size:10px; color:var(--text-dim); text-align:right; }
/* Action buttons per driver */
.drv-actions {
display:flex; gap:6px; flex-shrink:0;
}
.drv-progress { width:100px; flex-shrink:0; }
.drv-bar { height:3px; background:rgba(255,255,255,0.06); border-radius:2px; overflow:hidden; }
.drv-bar-fill { height:100%; border-radius:2px; transition:width .5s ease; }
.drv-bar-fill.ok { background:var(--green); width:100%; }
.drv-bar-fill.warn { background:var(--yellow); width:60%; }
.drv-bar-fill.err { background:var(--red); width:30%; }
.drv-actions { display:flex; gap:4px; flex-shrink:0; }
.drv-btn {
display:flex; align-items:center; gap:5px;
padding: 6px 14px;
border-radius: var(--r-sm);
border: 1px solid var(--border);
background: var(--surface-light);
color: var(--text-sec);
font-size: 11.5px; font-weight:600;
cursor:pointer;
transition: all .15s ease;
font-family:inherit;
display:flex; align-items:center; gap:4px;
padding:5px 10px; border-radius:var(--radius);
border:1px solid var(--border); background:var(--surface);
color:var(--text-sec); font-size:11px; font-weight:500;
cursor:pointer; transition:all .12s ease; font-family:inherit;
}
.drv-btn svg { width:13px; height:13px; }
.drv-btn:hover { border-color: var(--accent); color: var(--accent-light); }
.drv-btn img { width:13px; height:13px; }
.drv-btn:hover { background:var(--surface-hover); color:var(--text); }
.drv-btn.install-btn {
background: linear-gradient(135deg, var(--accent-dark), var(--accent));
border-color: var(--accent);
color: white;
background:var(--accent-bg); border-color:var(--accent-bg); color:white;
}
.drv-btn.install-btn:hover { box-shadow: 0 2px 8px var(--accent-glow); }
.drv-btn.install-btn:hover { background:var(--accent-hover); }
.drv-btn.installed-btn {
background: var(--green-bg);
border-color: rgba(16,185,129,0.3);
color: var(--green);
cursor: default;
.drv-btn.ok-btn {
background:var(--green-bg); border-color:rgba(108,203,95,0.2);
color:var(--green); cursor:default;
}
/* Status badges */
.drv-badge {
font-size:10px; font-weight:600;
padding: 2px 8px; border-radius:12px;
font-size:10px; font-weight:500; padding:1px 6px; border-radius:var(--radius-sm);
display:inline-flex; align-items:center; gap:3px;
}
.drv-badge svg { width:10px; height:10px; }
.drv-badge.signed { background:var(--green-bg); color:var(--green); }
.drv-badge.unsigned { background:var(--red-bg); color:var(--red); }
/* ---- CTA Bar (Download All) ---- */
/* ---- CTA Bar ---- */
.cta-bar {
padding: 16px 24px;
border-top: 1px solid var(--border);
background: rgba(10,22,40,0.8);
display: flex;
justify-content: center;
flex-shrink: 0;
padding:12px 20px; border-top:1px solid var(--border);
background:var(--bg); display:flex; justify-content:center; flex-shrink:0;
}
.cta-btn {
display:flex; align-items:center; gap:10px;
padding: 14px 48px;
background: linear-gradient(135deg, #059669, var(--green));
border:none; border-radius:12px;
color:white; font-size:15px; font-weight:700;
letter-spacing:1px;
cursor:pointer;
transition: all .25s ease;
font-family:inherit;
box-shadow: 0 4px 20px rgba(16,185,129,0.3);
display:flex; align-items:center; gap:8px;
padding:10px 36px;
background:var(--accent-bg); border:none;
border-radius:var(--radius); color:white;
font-size:14px; font-weight:600;
cursor:pointer; transition:all .15s ease; font-family:inherit;
}
.cta-btn svg { width:20px; height:20px; }
.cta-btn:hover { transform:translateY(-2px); box-shadow:0 6px 30px rgba(16,185,129,0.4); }
.cta-btn:hover { background:var(--accent-hover); }
.cta-btn:active { background:var(--accent-press); transform:scale(.98); }
.cta-count { background:rgba(255,255,255,0.15); padding:2px 8px; border-radius:var(--radius-sm); font-size:11px; }
.cta-count {
background: rgba(255,255,255,0.2);
padding: 2px 10px; border-radius:10px;
font-size:12px;
}
/* ---- Update Card ---- */
/* ---- Update Rows ---- */
.upd-row {
padding: 14px 18px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r);
margin-bottom: 8px;
transition: all .2s ease;
padding:10px 14px; background:var(--card); border:1px solid var(--border);
border-radius:var(--radius); margin-bottom:4px; transition:background .12s ease;
}
.upd-row:hover { border-color: rgba(59,130,246,0.2); }
.upd-row.pending { border-left: 3px solid var(--accent); }
.upd-row.done { opacity:.5; }
.upd-title { font-size:13.5px; font-weight:600; margin-bottom:5px; }
.upd-meta {
display:flex; gap:14px; flex-wrap:wrap;
font-size:11.5px; color:var(--text-dim);
}
.upd-tag { display:flex; align-items:center; gap:4px; }
.upd-tag svg { width:12px; height:12px; }
.upd-section {
font-size:12px; font-weight:700; text-transform:uppercase;
letter-spacing:.5px; margin:16px 0 8px;
display:flex; align-items:center; gap:6px;
}
.upd-section svg { width:14px; height:14px; }
.upd-section.pend { color:var(--accent-light); }
.upd-row:hover { background:var(--surface-hover); }
.upd-row.pending { border-left:3px solid var(--accent-bg); }
.upd-row.done { opacity:.45; }
.upd-title { font-size:13px; font-weight:600; margin-bottom:3px; }
.upd-meta { display:flex; gap:12px; flex-wrap:wrap; font-size:11px; color:var(--text-dim); }
.upd-tag { display:flex; align-items:center; gap:3px; }
.upd-tag img { width:12px; height:12px; }
.upd-section { font-size:12px; font-weight:600; margin:12px 0 6px; display:flex; align-items:center; gap:6px; }
.upd-section img { width:14px; height:14px; }
.upd-section.pend { color:var(--accent); }
.upd-section.inst { color:var(--green); }
/* ---- System Grid ---- */
.sys-grid {
display:grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
padding: 20px 24px;
overflow-y: auto;
flex: 1;
}
.sys-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r);
overflow: hidden;
}
.sys-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:12px 20px; overflow-y:auto; flex:1; }
.sys-card { background:var(--card); border:1px solid var(--border); border-radius:var(--radius); overflow:hidden; }
.sys-card-head {
display:flex; align-items:center; gap:8px;
padding: 12px 18px;
background: rgba(255,255,255,0.02);
border-bottom: 1px solid var(--border);
font-size: 12px; font-weight:700;
text-transform:uppercase; letter-spacing:.5px;
color: var(--text-sec);
}
.sys-card-head svg { width:16px; height:16px; color:var(--accent-light); }
.sys-row {
display:flex; justify-content:space-between;
padding: 10px 18px;
font-size: 12.5px;
border-bottom: 1px solid rgba(255,255,255,0.03);
display:flex; align-items:center; gap:6px;
padding:10px 14px; background:rgba(255,255,255,0.02);
border-bottom:1px solid var(--border);
font-size:12px; font-weight:600; color:var(--text-sec);
}
.sys-row { display:flex; justify-content:space-between; padding:7px 14px; font-size:12px; border-bottom:1px solid var(--border); }
.sys-row:last-of-type { border-bottom:none; }
.sys-row span:first-child { color:var(--text-dim); }
.sys-row span:last-child { font-weight:600; max-width:55%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sys-bar-wrap { padding:8px 18px 14px; }
.sys-bar { height:6px; background:rgba(255,255,255,0.05); border-radius:3px; overflow:hidden; }
.sys-bar-fill { height:100%; border-radius:3px; transition:width .8s ease; }
.ram-bar { background: linear-gradient(90deg, var(--green), #34d399); }
.disk-bar { background: linear-gradient(90deg, var(--accent), var(--accent-light)); }
.sys-bar-wrap { padding:6px 14px 10px; }
.sys-bar { height:4px; background:rgba(255,255,255,0.06); border-radius:2px; overflow:hidden; }
.sys-bar-fill { height:100%; border-radius:2px; transition:width .8s ease; }
.ram-bar { background:linear-gradient(90deg,var(--green),#6ccb5f); }
.disk-bar { background:linear-gradient(90deg,var(--accent-bg),var(--accent)); }
/* ---- Footer ---- */
.app-footer {
display:flex; justify-content:space-between; align-items:center;
padding: 8px 24px;
border-top: 1px solid var(--border);
background: rgba(10,22,40,0.6);
font-size: 11px; color: var(--text-dim);
flex-shrink: 0;
padding:6px 16px; border-top:1px solid var(--border);
background:var(--bg); font-size:11px; color:var(--text-dim); flex-shrink:0;
}
.footer-right { display:flex; gap:4px; }
.footer-right { display:flex; gap:2px; }
.footer-btn {
display:flex; align-items:center; gap:4px;
padding:4px 12px;
background:transparent; border:1px solid transparent;
border-radius:4px;
color:var(--text-dim); font-size:11px;
cursor:pointer;
font-family:inherit;
transition: all .15s ease;
display:flex; align-items:center; gap:4px; padding:3px 8px;
background:transparent; border:1px solid transparent; border-radius:var(--radius-sm);
color:var(--text-dim); font-size:11px; cursor:pointer;
font-family:inherit; transition:all .12s ease;
}
.footer-btn svg { width:12px; height:12px; }
.footer-btn:hover { color:var(--text-sec); border-color:var(--border); }
.footer-btn:hover { color:var(--text-sec); background:var(--surface-hover); }
.credit-link { color:var(--accent); text-decoration:none; font-weight:600; }
.credit-link:hover { text-decoration:underline; }
/* ---- Loading ---- */
.loading-overlay {
position:fixed; inset:0;
background: rgba(8,12,24,0.92);
backdrop-filter: blur(6px);
display:flex; align-items:center; justify-content:center;
z-index:1000;
background:rgba(32,32,32,0.85); backdrop-filter:blur(20px);
display:flex; align-items:center; justify-content:center; z-index:1000;
}
.loading-card {
text-align:center;
padding: 44px 56px;
background: var(--surface);
border:1px solid var(--border);
border-radius:16px;
box-shadow: 0 16px 48px rgba(0,0,0,.5);
}
.loading-spinner {
width:64px; height:64px;
margin:0 auto 20px;
position:relative;
text-align:center; padding:36px 48px;
background:var(--card); border:1px solid var(--border-light);
border-radius:var(--radius-lg);
box-shadow:0 8px 32px rgba(0,0,0,.5);
}
.loading-spinner { width:56px; height:56px; margin:0 auto 16px; position:relative; }
.spinner-ring {
position:absolute; inset:0;
border:3px solid var(--border);
border-top-color: var(--accent);
border-radius:50%;
animation: spin 1s linear infinite;
border-top-color:var(--accent-bg);
border-radius:50%; animation:spin .9s linear infinite;
}
@keyframes spin { to{transform:rotate(360deg)} }
.spinner-icon { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:var(--accent-light); }
.spinner-icon svg { width:24px; height:24px; }
.loading-title { font-size:15px; font-weight:700; margin-bottom:14px; }
.loading-dots { display:flex; justify-content:center; gap:5px; }
@keyframes spin{to{transform:rotate(360deg)}}
.loading-title { font-size:14px; font-weight:600; margin-bottom:10px; }
.loading-dots { display:flex; justify-content:center; gap:4px; }
.loading-dots span {
width:5px; height:5px; border-radius:50%;
background:var(--accent);
animation: dotPulse 1.4s ease-in-out infinite;
width:4px; height:4px; border-radius:50%; background:var(--accent-bg);
animation:dotPulse 1.4s ease-in-out infinite;
}
.loading-dots span:nth-child(2){animation-delay:.2s}
.loading-dots span:nth-child(3){animation-delay:.4s}
@keyframes dotPulse {
0%,80%,100%{opacity:.3;transform:scale(.8)}
40%{opacity:1;transform:scale(1)}
}
@keyframes dotPulse{0%,80%,100%{opacity:.3;transform:scale(.8)}40%{opacity:1;transform:scale(1)}}