Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</Application.Resources>
<Application.Styles>
<semi:SemiTheme Locale="en-US" />
<StyleInclude Source="avares://LocalLLMServerManager.Shared/Styles/GlassmorphicTheme.axaml" />
<StyleInclude Source="avares://LocalLLMServerManager.Shared/Styles/MatteTheme.axaml" />
</Application.Styles>
<TrayIcon.Icons>
<TrayIcons>
Expand Down
Binary file modified Assets/app-icon.ico
Binary file not shown.
Binary file added Assets/app-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified Assets/app_tray_icon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions Assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions LocalLLMServerManager.Shared/Services/IThemeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace LocalLLMServerManager.Shared.Services;

public enum AppTheme
{
MatteCarbon,
OledBlack,
Light
}

public interface IThemeService
{
AppTheme CurrentTheme { get; }
void SetTheme(AppTheme theme);
event EventHandler<AppTheme>? ThemeChanged;
}
131 changes: 131 additions & 0 deletions LocalLLMServerManager.Shared/Services/ThemeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;

namespace LocalLLMServerManager.Shared.Services;

public class ThemeService : IThemeService
{
private static ThemeService? _instance;
public static ThemeService Instance => _instance ??= new ThemeService();

private readonly IResourceDictionary? _resourceDictionary;

public AppTheme CurrentTheme { get; private set; } = AppTheme.MatteCarbon;

public event EventHandler<AppTheme>? ThemeChanged;

public ThemeService(IResourceDictionary? resourceDictionary = null)
{
_resourceDictionary = resourceDictionary;
}

public void SetTheme(AppTheme theme)
{
CurrentTheme = theme;

var resources = _resourceDictionary ?? Application.Current?.Resources;
if (resources != null)
{
ApplyThemeResources(resources, theme);
}

if (Application.Current != null)
{
Application.Current.RequestedThemeVariant = theme == AppTheme.Light ? ThemeVariant.Light : ThemeVariant.Dark;
}

ThemeChanged?.Invoke(this, theme);
}

public static void ApplyThemeResources(IResourceDictionary resources, AppTheme theme)
{
Color bgDark, bgSurface, bgCard, border, textMain, textMuted, primary, secondary, accent;

switch (theme)
{
case AppTheme.OledBlack:
bgDark = Color.Parse("#000000");
bgSurface = Color.Parse("#121212");
bgCard = Color.Parse("#18181b");
border = Color.Parse("#27272a");
textMain = Color.Parse("#f4f4f5");
textMuted = Color.Parse("#71717a");
primary = Color.Parse("#3b82f6");
secondary = Color.Parse("#60a5fa");
accent = Color.Parse("#60a5fa");
break;

case AppTheme.Light:
bgDark = Color.Parse("#ffffff");
bgSurface = Color.Parse("#f6f8fa");
bgCard = Color.Parse("#ffffff");
border = Color.Parse("#d0d7de");
textMain = Color.Parse("#1f2328");
textMuted = Color.Parse("#656d76");
primary = Color.Parse("#0969da");
secondary = Color.Parse("#218bff");
accent = Color.Parse("#218bff");
break;

case AppTheme.MatteCarbon:
default:
bgDark = Color.Parse("#0d1117");
bgSurface = Color.Parse("#161b22");
bgCard = Color.Parse("#1c2128");
border = Color.Parse("#30363d");
textMain = Color.Parse("#f0f6fc");
textMuted = Color.Parse("#8b949e");
primary = Color.Parse("#388bfd");
secondary = Color.Parse("#58a6ff");
accent = Color.Parse("#79c0ff");
break;
}

resources["BgDarkColor"] = bgDark;
resources["BgSurfaceColor"] = bgSurface;
resources["BgCardColor"] = bgCard;
resources["BorderColor"] = border;
resources["TextMainColor"] = textMain;
resources["TextMutedColor"] = textMuted;
resources["PrimaryColor"] = primary;
resources["SecondaryColor"] = secondary;
resources["AccentColor"] = accent;

SetOrUpdateBrush(resources, "BgDarkBrush", bgDark);
SetOrUpdateBrush(resources, "BgSurfaceBrush", bgSurface);
SetOrUpdateBrush(resources, "BgCardBrush", bgCard);
SetOrUpdateBrush(resources, "GlassBorderBrush", border);
SetOrUpdateBrush(resources, "BorderColorBrush", border);
SetOrUpdateBrush(resources, "BorderGlowBrush", primary, 0.4);
SetOrUpdateBrush(resources, "TextMainBrush", textMain);
SetOrUpdateBrush(resources, "TextMutedBrush", textMuted);
SetOrUpdateBrush(resources, "PrimaryBrush", primary);
SetOrUpdateBrush(resources, "SecondaryBrush", secondary);
SetOrUpdateBrush(resources, "AccentBrush", accent);
SetOrUpdateBrush(resources, "GlassBackgroundBrush", bgDark);
SetOrUpdateBrush(resources, "PrimaryGradientBrush", primary);
}

private static void SetOrUpdateBrush(IResourceDictionary resources, string key, Color color, double opacity = 1.0)
{
if (resources.TryGetResource(key, null, out var existing) && existing is SolidColorBrush existingBrush)
{
existingBrush.Color = color;
existingBrush.Opacity = opacity;
resources[key] = existingBrush;
}
else if (resources.TryGetValue(key, out var dictVal) && dictVal is SolidColorBrush dictBrush)
{
dictBrush.Color = color;
dictBrush.Opacity = opacity;
resources[key] = dictBrush;
}
else
{
resources[key] = new SolidColorBrush(color) { Opacity = opacity };
}
}
}
49 changes: 25 additions & 24 deletions LocalLLMServerManager.Shared/Styles/DesignTokens.axaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Color Definitions -->
<Color x:Key="BgDarkColor">#0b0e14</Color>
<Color x:Key="BgSurfaceColor">#161b26</Color>
<Color x:Key="BgCardColor">#1e2536</Color>
<Color x:Key="PrimaryColor">#8b5cf6</Color>
<Color x:Key="SecondaryColor">#06b6d4</Color>
<Color x:Key="AccentColor">#c084fc</Color>
<Color x:Key="BgDarkColor">#0d1117</Color>
<Color x:Key="BgSurfaceColor">#161b22</Color>
<Color x:Key="BgCardColor">#1c2128</Color>
<Color x:Key="BorderColor">#30363d</Color>
<Color x:Key="PrimaryColor">#388bfd</Color>
<Color x:Key="SecondaryColor">#58a6ff</Color>
<Color x:Key="AccentColor">#79c0ff</Color>
<Color x:Key="TextMainColor">#f0f6fc</Color>
<Color x:Key="TextMutedColor">#8b949e</Color>
<Color x:Key="OnlineColor">#238636</Color>
<Color x:Key="OfflineColor">#da3633</Color>
<Color x:Key="WarningColor">#d29922</Color>

<!-- Solid Brushes -->
<SolidColorBrush x:Key="BgDarkBrush" Color="{StaticResource BgDarkColor}" />
<SolidColorBrush x:Key="BgSurfaceBrush" Color="{StaticResource BgSurfaceColor}" Opacity="0.45" />
<SolidColorBrush x:Key="BgCardBrush" Color="{StaticResource BgCardColor}" Opacity="0.65" />
<SolidColorBrush x:Key="GlassBorderBrush" Color="#4b5563" Opacity="0.35" />
<SolidColorBrush x:Key="BorderGlowBrush" Color="#a78bfa" Opacity="0.25" />
<SolidColorBrush x:Key="BgSurfaceBrush" Color="{StaticResource BgSurfaceColor}" />
<SolidColorBrush x:Key="BgCardBrush" Color="{StaticResource BgCardColor}" />
<SolidColorBrush x:Key="GlassBorderBrush" Color="{StaticResource BorderColor}" />
<SolidColorBrush x:Key="BorderColorBrush" Color="{StaticResource BorderColor}" />
<SolidColorBrush x:Key="BorderGlowBrush" Color="#388bfd" Opacity="0.4" />
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource PrimaryColor}" />
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource SecondaryColor}" />
<SolidColorBrush x:Key="AccentBrush" Color="{StaticResource AccentColor}" />
<SolidColorBrush x:Key="TextMainBrush" Color="#f3f4f6" />
<SolidColorBrush x:Key="TextMutedBrush" Color="#9ca3af" />
<SolidColorBrush x:Key="OnlineBrush" Color="#22c55e" />
<SolidColorBrush x:Key="OfflineBrush" Color="#ef4444" />
<SolidColorBrush x:Key="TextMainBrush" Color="{StaticResource TextMainColor}" />
<SolidColorBrush x:Key="TextMutedBrush" Color="{StaticResource TextMutedColor}" />
<SolidColorBrush x:Key="OnlineBrush" Color="{StaticResource OnlineColor}" />
<SolidColorBrush x:Key="OfflineBrush" Color="{StaticResource OfflineColor}" />
<SolidColorBrush x:Key="WarningBrush" Color="{StaticResource WarningColor}" />

<!-- Gradient Brushes -->
<LinearGradientBrush x:Key="PrimaryGradientBrush" StartPoint="0%,50%" EndPoint="100%,50%">
<GradientStop Color="#8b5cf6" Offset="0.0" />
<GradientStop Color="#06b6d4" Offset="1.0" />
</LinearGradientBrush>

<RadialGradientBrush x:Key="GlassBackgroundBrush" Center="50%,50%" GradientOrigin="50%,50%" RadiusX="0.8" RadiusY="0.8">
<GradientStop Color="#1e1b4b" Offset="0.0" />
<GradientStop Color="#0b0e14" Offset="1.0" />
</RadialGradientBrush>
<!-- Solid Base Background & Legacy Fallbacks -->
<SolidColorBrush x:Key="GlassBackgroundBrush" Color="{StaticResource BgDarkColor}" />
<SolidColorBrush x:Key="PrimaryGradientBrush" Color="{StaticResource PrimaryColor}" />
</ResourceDictionary>
137 changes: 1 addition & 136 deletions LocalLLMServerManager.Shared/Styles/GlassmorphicTheme.axaml
Original file line number Diff line number Diff line change
@@ -1,139 +1,4 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://LocalLLMServerManager.Shared/Styles/DesignTokens.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Styles.Resources>
<!-- Glass Card Style -->
<Style Selector="Border.glass-card">
<Setter Property="Background" Value="{StaticResource BgCardBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource GlassBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Padding" Value="16" />
<Setter Property="BoxShadow" Value="0 8 32 0 #20000000" />
</Style>

<!-- Telemetry Pill Style -->
<Style Selector="Border.telemetry-pill">
<Setter Property="Background" Value="{StaticResource BgSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource GlassBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="16" />
<Setter Property="Padding" Value="10,6" />
</Style>

<!-- Primary Glowing Button Style -->
<Style Selector="Button.glass-primary">
<Setter Property="Background" Value="{StaticResource PrimaryGradientBrush}" />
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="16,10" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<Style Selector="Button.glass-primary /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="CornerRadius" Value="8" />
<Setter Property="BoxShadow" Value="0 4 15 0 #408b5cf6" />
</Style>
<Style Selector="Button.glass-primary:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="BoxShadow" Value="0 6 20 0 #608b5cf6" />
</Style>

<!-- Secondary Glass Button Style -->
<Style Selector="Button.glass-secondary">
<Setter Property="Background" Value="{StaticResource BgSurfaceBrush}" />
<Setter Property="Foreground" Value="{StaticResource TextMainBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource GlassBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="14,8" />
</Style>
<Style Selector="Button.glass-secondary:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{StaticResource BgCardBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource BorderGlowBrush}" />
</Style>

<!-- Glass Progress Bar Style -->
<Style Selector="ProgressBar.glass-progress">
<Setter Property="Background" Value="{StaticResource BgSurfaceBrush}" />
<Setter Property="Foreground" Value="{StaticResource PrimaryGradientBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource GlassBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="MinHeight" Value="10" />
</Style>

<!-- Glass Input TextBox Style -->
<Style Selector="TextBox.glass-input">
<Setter Property="Background" Value="{StaticResource BgSurfaceBrush}" />
<Setter Property="Foreground" Value="{StaticResource TextMainBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource GlassBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Padding" Value="10,8" />
</Style>
<Style Selector="TextBox.glass-input:focus /template/ Border#PART_BorderElement">
<Setter Property="BorderBrush" Value="{StaticResource BorderGlowBrush}" />
<Setter Property="Background" Value="{StaticResource BgCardBrush}" />
</Style>

<!-- Glass TabControl Navigation Bar Style -->
<Style Selector="TabControl">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Padding" Value="0" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<DockPanel>
<Border DockPanel.Dock="Top"
Background="{StaticResource BgSurfaceBrush}"
CornerRadius="12"
Margin="0,0,0,16"
Padding="6"
HorizontalAlignment="Left">
<ItemsPresenter Name="PART_ItemsPresenter"
ItemsPanel="{TemplateBinding ItemsPanel}" />
</Border>
<ContentPresenter Name="PART_SelectedContentHost"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding SelectedContentTemplate}" />
</DockPanel>
</Border>
</ControlTemplate>
</Setter>
</Style>

<!-- Glass TabItem Style -->
<Style Selector="TabItem">
<Setter Property="Foreground" Value="{StaticResource TextMutedBrush}" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Padding" Value="16,10" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="Margin" Value="2,0" />
<Setter Property="MinHeight" Value="38" />
</Style>
<Style Selector="TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{StaticResource BgCardBrush}" />
<Setter Property="Foreground" Value="{StaticResource TextMainBrush}" />
</Style>
<Style Selector="TabItem:selected">
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{StaticResource PrimaryGradientBrush}" />
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="BoxShadow" Value="0 4 12 0 #408b5cf6" />
</Style>
<StyleInclude Source="avares://LocalLLMServerManager.Shared/Styles/MatteTheme.axaml" />
</Styles>
Loading
Loading