init
This commit is contained in:
6
src/components/__init__.py
Normal file
6
src/components/__init__.py
Normal 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']
|
||||
19
src/components/bottom_nav.py
Normal file
19
src/components/bottom_nav.py
Normal 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')
|
||||
49
src/components/circular_progress.py
Normal file
49
src/components/circular_progress.py
Normal 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
38
src/components/header.py
Normal 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
48
src/components/sidebar.py
Normal 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}')
|
||||
Reference in New Issue
Block a user