Update SVG icons with cleaner, modern designs using stroke-based paths

This commit is contained in:
devmatrix 2026-02-20 18:09:00 +00:00
parent 9aa36bb608
commit b8fb5535fd
4 changed files with 137 additions and 52 deletions

View File

@ -19,37 +19,8 @@
"sensor_preference": "auto", "sensor_preference": "auto",
"fans": {}, "fans": {},
"fan_groups": {}, "fan_groups": {},
"active_curve": "Performance",
"fan_curves": { "fan_curves": {
"Default": {
"points": [
{
"temp": 30,
"speed": 15
},
{
"temp": 40,
"speed": 25
},
{
"temp": 50,
"speed": 40
},
{
"temp": 60,
"speed": 60
},
{
"temp": 70,
"speed": 80
},
{
"temp": 80,
"speed": 100
}
],
"sensor_source": "cpu",
"applies_to": "all"
},
"Balanced": { "Balanced": {
"points": [ "points": [
{ {
@ -183,8 +154,37 @@
], ],
"sensor_source": "cpu", "sensor_source": "cpu",
"applies_to": "all" "applies_to": "all"
},
"Default": {
"points": [
{
"temp": 30,
"speed": 15
},
{
"temp": 40,
"speed": 25
},
{
"temp": 50,
"speed": 40
},
{
"temp": 60,
"speed": 60
},
{
"temp": 70,
"speed": 80
},
{
"temp": 80,
"speed": 100
}
],
"sensor_source": "cpu",
"applies_to": "all"
} }
}, },
"theme": "dark", "theme": "dark"
"active_curve": "Performance"
} }

View File

@ -1,5 +1,5 @@
INFO: Started server process [36170] INFO: Started server process [42005]
INFO: Waiting for application startup. INFO: Waiting for application startup.
INFO: Application startup complete. INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: 127.0.0.1:49684 - "GET / HTTP/1.1" 200 OK INFO: 127.0.0.1:47014 - "GET / HTTP/1.1" 200 OK

85
static/icons.svg Normal file
View File

@ -0,0 +1,85 @@
<!-- Modern, clean SVG icons for IPMI Controller -->
<svg style="display:none;" xmlns="http://www.w3.org/2000/svg">
<!-- Thermometer Icon -->
<symbol id="icon-thermometer" viewBox="0 0 24 24">
<path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="11.5" cy="18.5" r="2" fill="currentColor"/>
</symbol>
<!-- Server Icon -->
<symbol id="icon-server" viewBox="0 0 24 24">
<rect x="2" y="3" width="20" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="1.5"/>
<rect x="2" y="11" width="20" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="1.5"/>
<rect x="2" y="19" width="20" height="3" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.5"/>
<circle cx="6" cy="6" r="1" fill="currentColor"/>
<circle cx="6" cy="14" r="1" fill="currentColor"/>
</symbol>
<!-- Fan Icon -->
<symbol id="icon-fan" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M12 12c0-3 2-5 5-5s5 2 5 5-2 5-5 5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<path d="M12 12c0 3-2 5-5 5s-5-2-5-5 2-5 5-5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<path d="M12 12c3 0 5-2 5-5s-2-5-5-5-5 2-5 5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<path d="M12 12c-3 0-5 2-5 5s2 5 5 5 5-2 5-5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</symbol>
<!-- Clock/Mode Icon -->
<symbol id="icon-clock" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M12 7v5l3 3" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<!-- Sensors/List Icon -->
<symbol id="icon-sensors" viewBox="0 0 24 24">
<path d="M3 6h18M3 12h18M3 18h18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="7" cy="6" r="1.5" fill="currentColor"/>
<circle cx="7" cy="12" r="1.5" fill="currentColor"/>
<circle cx="7" cy="18" r="1.5" fill="currentColor"/>
</symbol>
<!-- Lock/Password Icon -->
<symbol id="icon-lock" viewBox="0 0 24 24">
<rect x="5" y="11" width="14" height="10" rx="2" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</symbol>
<!-- Logout Icon -->
<symbol id="icon-logout" viewBox="0 0 24 24">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 17l5-5-5-5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 12H9" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<!-- Sun/Theme Icon -->
<symbol id="icon-sun" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="4" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</symbol>
<!-- Controls/Settings Icon -->
<symbol id="icon-controls" viewBox="0 0 24 24">
<circle cx="6" cy="12" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/>
<circle cx="18" cy="6" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/>
<circle cx="18" cy="18" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M9 12h3M15 6h-3M15 18h-3" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</symbol>
<!-- Search/Identify Icon -->
<symbol id="icon-search" viewBox="0 0 24 24">
<circle cx="11" cy="11" r="7" fill="none" stroke="currentColor" stroke-width="1.5"/>
<path d="M21 21l-4.35-4.35" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<!-- Check/Success Icon -->
<symbol id="icon-check" viewBox="0 0 24 24">
<path d="M20 6L9 17l-5-5" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<!-- X/Error Icon -->
<symbol id="icon-x" viewBox="0 0 24 24">
<path d="M18 6L6 18M6 6l12 12" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -476,37 +476,37 @@ def get_html(theme="dark"):
<div class="container"> <div class="container">
<header> <header>
<div class="header-top"> <div class="header-top">
<h1><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a2 2 0 012 2v.35a7 7 0 015.65 6.65 1 1 0 01-2 0 5 5 0 00-10 0 1 1 0 01-2 0A7 7 0 019.35 4.35 2 2 0 0112 2zm0 6a4 4 0 00-4 4v7h8v-7a4 4 0 00-4-4z"/></svg></span>IPMI Controller</h1> <h1><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z"/><circle cx="11.5" cy="18.5" r="2" fill="currentColor"/></svg></span>IPMI Controller</h1>
<div class="header-actions"> <div class="header-actions">
<button class="secondary small" onclick="toggleTheme()"><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 4a1 1 0 011 1v2a1 1 0 11-2 0V5a1 1 0 011-1zm0 14a5 5 0 100-10 5 5 0 000 10zm0-2a3 3 0 110-6 3 3 0 010 6zM4.93 4.93a1 1 0 011.41 0l1.42 1.42a1 1 0 11-1.41 1.41L4.93 6.34a1 1 0 010-1.41zm0 14.14a1 1 0 010-1.41l1.42-1.42a1 1 0 111.41 1.41l-1.42 1.42a1 1 0 01-1.41 0zM19.07 4.93a1 1 0 010 1.41l-1.42 1.42a1 1 0 11-1.41-1.41l1.42-1.42a1 1 0 011.41 0zM12 18a1 1 0 011 1v2a1 1 0 11-2 0v-2a1 1 0 011-1z"/></svg></span>Theme</button> <button class="secondary small" onclick="toggleTheme()"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2m16 0h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" stroke-linecap="round"/></svg></span>Theme</button>
<button class="secondary small" onclick="showPasswordModal()"><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a5 5 0 00-5 5v2H6a2 2 0 00-2 2v9a2 2 0 002 2h12a2 2 0 002-2v-9a2 2 0 00-2-2h-1V7a5 5 0 00-5-5zm-3 5a3 3 0 116 0v2H9V7zm3 7a1 1 0 01-1 1v2a1 1 0 112 0v-2a1 1 0 01-1-1z"/></svg></span>Password</button> <button class="secondary small" onclick="showPasswordModal()"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4" stroke-linecap="round"/></svg></span>Password</button>
<button class="secondary small" onclick="logout()"><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M10 3H6a2 2 0 00-2 2v14a2 2 0 002 2h4M17 16l4-4m0 0l-4-4m4 4H10"/></svg></span>Logout</button> <button class="secondary small" onclick="logout()"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" stroke-linecap="round" stroke-linejoin="round"/><path d="M16 17l5-5-5-5" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 12H9" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Logout</button>
</div> </div>
</div> </div>
<div class="status-bar"> <div class="status-bar">
<div class="status-item" id="status-ipmi"> <div class="status-item" id="status-ipmi">
<div class="icon"><svg viewBox="0 0 24 24"><path d="M4 4h16v12H4V4zm2 2v8h12V6H6zm-2 12h16v2H4v-2zm4-10h2v6H8V8zm4 0h2v6h-2V8zm4 0h2v6h-2V8z"/></svg></div> <div class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="6" rx="2"/><rect x="2" y="11" width="20" height="6" rx="2"/><rect x="2" y="19" width="20" height="3" rx="1.5"/><circle cx="6" cy="6" r="1" fill="currentColor"/><circle cx="6" cy="14" r="1" fill="currentColor"/></svg></div>
<div class="label">IPMI</div> <div class="label">IPMI</div>
<div class="value" id="val-ipmi">-</div> <div class="value" id="val-ipmi">-</div>
</div> </div>
<div class="status-item" id="status-mode"> <div class="status-item" id="status-mode">
<div class="icon"><svg viewBox="0 0 24 24"><path d="M12 2a10 10 0 100 20 10 10 0 000-20zm0 18a8 8 0 110-16 8 8 0 010 16zm1-8h4v2h-6V7h2v5z"/></svg></div> <div class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 3" stroke-linecap="round"/></svg></div>
<div class="label">Mode</div> <div class="label">Mode</div>
<div class="value" id="val-mode">-</div> <div class="value" id="val-mode">-</div>
</div> </div>
<div class="status-item" id="status-temp"> <div class="status-item" id="status-temp">
<div class="icon"><svg viewBox="0 0 24 24"><path d="M12 2a2 2 0 012 2v.35a7 7 0 015.65 6.65 1 1 0 01-2 0 5 5 0 00-10 0 1 1 0 01-2 0A7 7 0 019.35 4.35 2 2 0 0112 2zm0 6a4 4 0 00-4 4v7h8v-7a4 4 0 00-4-4z"/></svg></div> <div class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z"/><circle cx="11.5" cy="18.5" r="2" fill="currentColor"/></svg></div>
<div class="label">Max Temp</div> <div class="label">Max Temp</div>
<div class="value" id="val-temp">-</div> <div class="value" id="val-temp">-</div>
</div> </div>
<div class="status-item" id="status-fans"> <div class="status-item" id="status-fans">
<div class="icon"><svg viewBox="0 0 24 24"><path d="M12 2a5 5 0 00-5 5v3H5a2 2 0 00-2 2v8a2 2 0 002 2h14a2 2 0 002-2v-8a2 2 0 00-2-2h-2V7a5 5 0 00-5-5zm-3 5a3 3 0 116 0v3H9V7zm6 7a1 1 0 01-1 1 1 1 0 01-1-1 1 1 0 011-1 1 1 0 011 1z"/></svg></div> <div class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M12 12c0-3 2-5 5-5s5 2 5 5-2 5-5 5" stroke-linecap="round"/><path d="M12 12c0 3-2 5-5 5s-5-2-5-5 2-5 5-5" stroke-linecap="round"/><path d="M12 12c3 0 5-2 5-5s-2-5-5-5-5 2-5 5" stroke-linecap="round"/><path d="M12 12c-3 0-5 2-5 5s2 5 5 5 5-2 5-5" stroke-linecap="round"/></svg></div>
<div class="label">Fan Speed</div> <div class="label">Fan Speed</div>
<div class="value" id="val-fans">-</div> <div class="value" id="val-fans">-</div>
</div> </div>
<div class="status-item" id="status-sensors"> <div class="status-item" id="status-sensors">
<div class="icon"><svg viewBox="0 0 24 24"><path d="M4 6h16v2H4V6zm0 5h16v2H4v-2zm0 5h16v2H4v-2z"/></svg></div> <div class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 6h18M3 12h18M3 18h18" stroke-linecap="round"/><circle cx="7" cy="6" r="1.5" fill="currentColor"/><circle cx="7" cy="12" r="1.5" fill="currentColor"/><circle cx="7" cy="18" r="1.5" fill="currentColor"/></svg></div>
<div class="label">Sensors</div> <div class="label">Sensors</div>
<div class="value" id="val-sensors">-</div> <div class="value" id="val-sensors">-</div>
</div> </div>
@ -515,7 +515,7 @@ def get_html(theme="dark"):
<!-- Quick Controls --> <!-- Quick Controls -->
<div class="card"> <div class="card">
<h2><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a10 10 0 100 20 10 10 0 000-20zm0 18a8 8 0 110-16 8 8 0 010 16zm1-8h4v2h-6V7h2v5z"/></svg></span>Quick Controls</h2> <h2><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="6" cy="12" r="3"/><circle cx="18" cy="6" r="3"/><circle cx="18" cy="18" r="3"/><path d="M9 12h3m3-6h-3m3 12h-3" stroke-linecap="round"/></svg></span>Quick Controls</h2>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:15px;"> <div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:15px;">
<button class="success" onclick="setAuto(true)">Start Auto</button> <button class="success" onclick="setAuto(true)">Start Auto</button>
<button class="danger" onclick="setAuto(false)">Stop Auto</button> <button class="danger" onclick="setAuto(false)">Stop Auto</button>
@ -533,7 +533,7 @@ def get_html(theme="dark"):
<!-- Temperatures --> <!-- Temperatures -->
<div class="card"> <div class="card">
<h2><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a2 2 0 012 2v.35a7 7 0 015.65 6.65 1 1 0 01-2 0 5 5 0 00-10 0 1 1 0 01-2 0A7 7 0 019.35 4.35 2 2 0 0112 2zm0 6a4 4 0 00-4 4v7h8v-7a4 4 0 00-4-4z"/></svg></span>Temperatures</h2> <h2><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 14.76V3.5a2.5 2.5 0 0 0-5 0v11.26a4.5 4.5 0 1 0 5 0z"/><circle cx="11.5" cy="18.5" r="2" fill="currentColor"/></svg></span>Temperatures</h2>
<div class="temp-grid" id="temp-grid"> <div class="temp-grid" id="temp-grid">
<div class="temp-item"><span>Loading...</span></div> <div class="temp-item"><span>Loading...</span></div>
</div> </div>
@ -541,7 +541,7 @@ def get_html(theme="dark"):
<!-- Fans --> <!-- Fans -->
<div class="card"> <div class="card">
<h2><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a5 5 0 00-5 5v3H5a2 2 0 00-2 2v8a2 2 0 002 2h14a2 2 0 002-2v-8a2 2 0 00-2-2h-2V7a5 5 0 00-5-5zm-3 5a3 3 0 116 0v3H9V7z"/></svg></span>Fans</h2> <h2><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M12 12c0-3 2-5 5-5s5 2 5 5-2 5-5 5" stroke-linecap="round"/><path d="M12 12c0 3-2 5-5 5s-5-2-5-5 2-5 5-5" stroke-linecap="round"/><path d="M12 12c3 0 5-2 5-5s-2-5-5-5-5 2-5 5" stroke-linecap="round"/><path d="M12 12c-3 0-5 2-5 5s2 5 5 5 5-2 5-5" stroke-linecap="round"/></svg></span>Fans</h2>
<div class="fan-grid" id="fan-grid"> <div class="fan-grid" id="fan-grid">
<div class="fan-card">Loading...</div> <div class="fan-card">Loading...</div>
</div> </div>
@ -550,12 +550,12 @@ def get_html(theme="dark"):
<!-- Settings --> <!-- Settings -->
<div class="card"> <div class="card">
<div class="tabs"> <div class="tabs">
<button class="tab active" onclick="showTab('ipmi')"><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M4 4h16v12H4V4zm2 2v8h12V6H6zm-2 12h16v2H4v-2z"/></svg></span>IPMI</button> <button class="tab active" onclick="showTab('ipmi')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="6" rx="2"/><rect x="2" y="11" width="20" height="6" rx="2"/><rect x="2" y="19" width="20" height="3" rx="1.5"/></svg></span>IPMI</button>
<button class="tab" onclick="showTab('http')">🌐 HTTP</button> <button class="tab" onclick="showTab('http')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span>HTTP</button>
<button class="tab" onclick="showTab('control')"> Control</button> <button class="tab" onclick="showTab('control')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>Control</button>
<button class="tab" onclick="showTab('fans')"><span class="icon-svg"><svg viewBox="0 0 24 24"><path d="M12 2a5 5 0 00-5 5v3H5a2 2 0 00-2 2v8a2 2 0 002 2h14a2 2 0 002-2v-8a2 2 0 00-2-2h-2V7a5 5 0 00-5-5zm-3 5a3 3 0 116 0v3H9V7z"/></svg></span>Fans</button> <button class="tab" onclick="showTab('fans')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M12 12c0-3 2-5 5-5s5 2 5 5-2 5-5 5" stroke-linecap="round"/><path d="M12 12c0 3-2 5-5 5s-5-2-5-5 2-5 5-5" stroke-linecap="round"/><path d="M12 12c3 0 5-2 5-5s-2-5-5-5-5 2-5 5" stroke-linecap="round"/><path d="M12 12c-3 0-5 2-5 5s2 5 5 5 5-2 5-5" stroke-linecap="round"/></svg></span>Fans</button>
<button class="tab" onclick="showTab('curves')">📈 Curves</button> <button class="tab" onclick="showTab('curves')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M3 3v18h18"/><path d="M19 9l-5 5-4-4-3 3" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Curves</button>
<button class="tab" onclick="showTab('logs')">📝 Logs</button> <button class="tab" onclick="showTab('logs')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg></span>Logs</button>
</div> </div>
<div id="tab-ipmi" class="tab-content active"> <div id="tab-ipmi" class="tab-content active">