This commit is contained in:
2025-09-17 08:26:56 +02:00
parent 3ba44e47c1
commit 7af7ba28a0
23 changed files with 2420 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
from .header import Header
from .sidebar import Sidebar
from .bottom_nav import BottomNav
from .circular_progress import MetricCircle, LargeMetricCircle, ColorfulMetricCard
__all__ = ['Header', 'Sidebar', 'BottomNav', 'MetricCircle', 'LargeMetricCircle', 'ColorfulMetricCard']

View File

@@ -0,0 +1,19 @@
from nicegui import ui
class BottomNav:
def __init__(self):
with ui.footer().classes('bottom-nav fixed-bottom') as footer:
with ui.row().classes('w-full justify-around items-center py-2'):
self._nav_item('dashboard', 'Dashboard', '/', active=True)
self._nav_item('smart_toy', 'Ollama', '/ollama')
self._nav_item('terminal', 'Processes', '/processes')
self._nav_item('settings', 'Settings', '/settings')
def _nav_item(self, icon: str, label: str, route: str, active: bool = False):
def navigate():
ui.navigate.to(route)
with ui.column().classes('items-center cursor-pointer').on('click', navigate):
ui.icon(icon, size='md').props(f'color={"cyan" if active else "grey-5"}')
ui.label(label).classes(f'text-xs {"text-cyan" if active else "text-grey-5"} mt-1')

View File

@@ -0,0 +1,49 @@
from nicegui import ui
class MetricCircle:
def __init__(self, title: str, value: str, percentage: float, color: str, icon: str):
with ui.card().classes('metric-card p-4 text-center'):
with ui.column().classes('items-center gap-2'):
# Icon at top
ui.icon(icon, size='md', color=color)
# Title
ui.label(title).classes('text-sm text-grey-5 font-medium')
# Circular progress - simplified
ui.circular_progress(
value=percentage,
size='60px',
color=color
)
# Value
ui.label(value).classes('text-lg font-bold text-white')
class LargeMetricCircle:
def __init__(self, title: str, value: str, percentage: float, color: str):
with ui.card().classes('metric-card p-6 text-center'):
with ui.column().classes('items-center gap-3'):
# Title
ui.label(title).classes('text-sm text-grey-5 font-medium uppercase tracking-wide')
# Large circular progress - simplified
ui.circular_progress(
value=percentage,
size='120px',
color=color
)
# Value below
ui.label(f'{int(percentage * 100)}%').classes('text-2xl font-bold text-white')
ui.label(value).classes('text-xs text-grey-5')
class ColorfulMetricCard:
def __init__(self, title: str, icon: str, color: str):
with ui.card().classes(f'p-4 text-center animate-fade-in').style(f'background: linear-gradient(135deg, {color}20 0%, {color}10 100%); border: 1px solid {color}40'):
with ui.column().classes('items-center gap-2'):
ui.icon(icon, size='xl').style(f'color: {color}')
ui.label(title).classes('text-sm font-medium text-white')

38
src/components/header.py Normal file
View File

@@ -0,0 +1,38 @@
from nicegui import ui
from utils import data_manager
class Header(ui.header):
def __init__(self):
super().__init__(fixed=True, elevated=False)
with self.classes('bg-transparent'):
with ui.row().classes('w-full items-center justify-between px-6 py-3'):
# Left side - minimal branding
with ui.row().classes('items-center gap-3'):
ui.label('ArchGPU Frontend').classes('text-xl font-bold text-white')
ui.chip('Live', icon='circle', color='green').props('size=sm outline')
# Right side - system status only
with ui.row().classes('items-center gap-4'):
# Get real-time data
dashboard_data = data_manager.get_dashboard_data()
# System load indicator
with ui.row().classes('items-center gap-2'):
ui.icon('memory', size='sm', color='cyan')
ui.label(f'CPU: {dashboard_data["cpu"]["percent"]}%').classes('text-sm text-white')
with ui.row().classes('items-center gap-2'):
ui.icon('gpu_on', size='sm', color='orange')
if dashboard_data['gpu']['available']:
ui.label(f'GPU: {dashboard_data["gpu"]["percent"]}%').classes('text-sm text-white')
else:
ui.label('GPU: N/A').classes('text-sm text-white')
with ui.row().classes('items-center gap-2'):
ui.icon('thermostat', size='sm', color='red')
if dashboard_data['gpu']['available'] and dashboard_data['gpu']['temperature'] > 0:
ui.label(f'{dashboard_data["gpu"]["temperature"]}°C').classes('text-sm text-white')
else:
ui.label('--°C').classes('text-sm text-white')

48
src/components/sidebar.py Normal file
View File

@@ -0,0 +1,48 @@
from nicegui import ui
class Sidebar:
def __init__(self, current_route='/'):
with ui.left_drawer(value=True, bordered=True, fixed=True).classes('w-64') as drawer:
drawer.style('background: #252837; border-right: 1px solid #374151;')
with ui.column().classes('w-full h-full p-4'):
# Navigation sections
ui.label('MAIN').classes('text-xs text-grey-5 font-bold tracking-wide mb-2')
with ui.column().classes('gap-1 mb-6'):
self._nav_item('Dashboard', 'dashboard', '/', active=(current_route == '/'))
self._nav_item('System Overview', 'monitor', '/system', active=(current_route == '/system'))
ui.label('MANAGEMENT').classes('text-xs text-grey-5 font-bold tracking-wide mb-2')
with ui.column().classes('gap-1 mb-6'):
self._nav_item('Ollama Manager', 'smart_toy', '/ollama', active=(current_route == '/ollama'))
self._nav_item('Process Manager', 'terminal', '/processes', active=(current_route == '/processes'))
self._nav_item('Network Monitor', 'router', '/network', active=(current_route == '/network'))
self._nav_item('Package Manager', 'inventory_2', '/packages', active=(current_route == '/packages'))
ui.label('TOOLS').classes('text-xs text-grey-5 font-bold tracking-wide mb-2')
with ui.column().classes('gap-1 mb-6'):
self._nav_item('Log Viewer', 'description', '/logs', active=(current_route == '/logs'))
self._nav_item('System Info', 'info', '/info', active=(current_route == '/info'))
ui.space()
# Bottom section
ui.separator().classes('my-4')
self._nav_item('Settings', 'settings', '/settings', active=(current_route == '/settings'))
def _nav_item(self, label: str, icon: str, route: str, active: bool = False):
def navigate():
ui.navigate.to(route)
bg_class = 'bg-cyan-600 bg-opacity-20' if active else ''
text_color = 'text-cyan' if active else 'text-grey-5 hover:text-white'
icon_color = 'cyan' if active else 'grey-5'
with ui.row().classes(f'w-full items-center gap-3 px-3 py-2 rounded-lg cursor-pointer {bg_class}').on('click', navigate):
ui.icon(icon, size='sm', color=icon_color)
ui.label(label).classes(f'text-sm {text_color}')