mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-10-29 20:20:20 +00:00 
			
		
		
		
	Added color themes (dark & light)
This commit is contained in:
		
							parent
							
								
									0ad7b8d4dd
								
							
						
					
					
						commit
						c96e55e471
					
				| @ -45,7 +45,7 @@ | ||||
|              | ||||
|             @if (!this.FooterButtons.Any(x => x.Type is ButtonTypes.SEND_TO)) | ||||
|             { | ||||
|                 <MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Color="Color.Info"> | ||||
|                 <MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded"> | ||||
|                     @foreach (var assistant in Enum.GetValues<Components>().OrderBy(n => n.Name().Length)) | ||||
|                     { | ||||
|                         if (assistant is Components.NONE || this.Component == assistant) | ||||
| @ -77,7 +77,7 @@ | ||||
|                         break; | ||||
| 
 | ||||
|                     case SendToButton sendToButton: | ||||
|                         <MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Color="Color.Info"> | ||||
|                         <MudMenu StartIcon="@Icons.Material.Filled.Apps" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="Send to ..." Variant="Variant.Filled" Style="@this.GetSendToColor()" Class="rounded"> | ||||
|                             @foreach (var assistant in Enum.GetValues<Components>().OrderBy(n => n.Name().Length)) | ||||
|                             { | ||||
|                                 if(assistant is Components.NONE || sendToButton.Self == assistant) | ||||
| @ -96,7 +96,7 @@ | ||||
|                 Copy result | ||||
|             </MudButton> | ||||
|              | ||||
|             <MudButton Variant="Variant.Filled" Color="Color.Warning" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()"> | ||||
|             <MudButton Variant="Variant.Filled" Style="@this.GetResetColor()" StartIcon="@Icons.Material.Filled.Refresh" OnClick="() => this.InnerResetForm()"> | ||||
|                 Reset | ||||
|             </MudButton> | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ using RustService = AIStudio.Tools.RustService; | ||||
| 
 | ||||
| namespace AIStudio.Assistants; | ||||
| 
 | ||||
| public abstract partial class AssistantBase : ComponentBase | ||||
| public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver, IDisposable | ||||
| { | ||||
|     [Inject] | ||||
|     protected SettingsManager SettingsManager { get; init; } = null!; | ||||
| @ -31,6 +31,12 @@ public abstract partial class AssistantBase : ComponentBase | ||||
|     [Inject] | ||||
|     protected ILogger<AssistantBase> Logger { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private MudTheme ColorTheme { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private MessageBus MessageBus { get; init; } = null!; | ||||
|      | ||||
|     internal const string AFTER_RESULT_DIV_ID = "afterAssistantResult"; | ||||
|     internal const string RESULT_DIV_ID = "assistantResult"; | ||||
|      | ||||
| @ -91,6 +97,10 @@ public abstract partial class AssistantBase : ComponentBase | ||||
|         this.MightPreselectValues(); | ||||
|         this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component); | ||||
|         this.currentProfile = this.SettingsManager.GetPreselectedProfile(this.Component); | ||||
|          | ||||
|         this.MessageBus.RegisterComponent(this); | ||||
|         this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]); | ||||
|          | ||||
|         await base.OnInitializedAsync(); | ||||
|     } | ||||
| 
 | ||||
| @ -114,7 +124,28 @@ public abstract partial class AssistantBase : ComponentBase | ||||
| 
 | ||||
|     #endregion | ||||
|      | ||||
|     private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder() : string.Empty; | ||||
|     #region Implementation of IMessageBusReceiver | ||||
| 
 | ||||
|     public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|             case Event.COLOR_THEME_CHANGED: | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|         } | ||||
|          | ||||
|         return Task.CompletedTask; | ||||
|     } | ||||
| 
 | ||||
|     public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data) | ||||
|     { | ||||
|         return Task.FromResult<TResult?>(default); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
| 
 | ||||
|     private string SubmitButtonStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).StyleBorder(this.SettingsManager) : string.Empty; | ||||
|      | ||||
|     protected string? ValidatingProvider(AIStudio.Settings.Provider provider) | ||||
|     { | ||||
| @ -251,4 +282,25 @@ public abstract partial class AssistantBase : ComponentBase | ||||
|         this.StateHasChanged(); | ||||
|         this.form?.ResetValidation(); | ||||
|     } | ||||
| 
 | ||||
|     private string GetResetColor() => this.SettingsManager.IsDarkMode switch | ||||
|     { | ||||
|         true => $"background-color: #804000", | ||||
|         false => $"background-color: {this.ColorTheme.GetCurrentPalette(this.SettingsManager).Warning.Value}", | ||||
|     }; | ||||
|      | ||||
|     private string GetSendToColor() => this.SettingsManager.IsDarkMode switch | ||||
|     { | ||||
|         true => $"background-color: #004080", | ||||
|         false => $"background-color: {this.ColorTheme.GetCurrentPalette(this.SettingsManager).InfoLighten}", | ||||
|     }; | ||||
| 
 | ||||
|     #region Implementation of IDisposable | ||||
| 
 | ||||
|     public void Dispose() | ||||
|     { | ||||
|         this.MessageBus.Unregister(this); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| <MudCard Outlined="@true" Style="border-width: 2px; border-color: #0d47a1; border-radius: 12px; border-style: solid; max-width: 20em;"> | ||||
| <MudCard Outlined="@true" Style="@this.BlockStyle"> | ||||
|     <MudCardHeader> | ||||
|         <CardHeaderContent> | ||||
|             <MudStack AlignItems="AlignItems.Center" Row="@true"> | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| using Microsoft.AspNetCore.Components; | ||||
| 
 | ||||
| namespace AIStudio.Components; | ||||
| 
 | ||||
| public partial class AssistantBlock : ComponentBase | ||||
| public partial class AssistantBlock : ComponentBase, IMessageBusReceiver, IDisposable | ||||
| { | ||||
|     [Parameter] | ||||
|     public string Name { get; set; } = string.Empty; | ||||
| @ -18,4 +20,63 @@ public partial class AssistantBlock : ComponentBase | ||||
|      | ||||
|     [Parameter] | ||||
|     public string Link { get; set; } = string.Empty; | ||||
|      | ||||
|     [Inject] | ||||
|     private MudTheme ColorTheme { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private SettingsManager SettingsManager { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private MessageBus MessageBus { get; init; } = null!; | ||||
| 
 | ||||
|     #region Overrides of ComponentBase | ||||
| 
 | ||||
|     protected override async Task OnInitializedAsync() | ||||
|     { | ||||
|         this.MessageBus.RegisterComponent(this); | ||||
|         this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]); | ||||
|          | ||||
|         await base.OnInitializedAsync(); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
|      | ||||
|     #region Implementation of IMessageBusReceiver | ||||
| 
 | ||||
|     public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|             case Event.COLOR_THEME_CHANGED: | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|         } | ||||
|          | ||||
|         return Task.CompletedTask; | ||||
|     } | ||||
| 
 | ||||
|     public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data) | ||||
|     { | ||||
|         return Task.FromResult<TResult?>(default); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
| 
 | ||||
|     private string BorderColor => this.SettingsManager.IsDarkMode switch | ||||
|     { | ||||
|         true => this.ColorTheme.GetCurrentPalette(this.SettingsManager).GrayLight, | ||||
|         false => this.ColorTheme.GetCurrentPalette(this.SettingsManager).Primary.Value, | ||||
|     }; | ||||
| 
 | ||||
|     private string BlockStyle => $"border-width: 2px; border-color: {this.BorderColor}; border-radius: 12px; border-style: solid; max-width: 20em;"; | ||||
|      | ||||
|     #region Implementation of IDisposable | ||||
| 
 | ||||
|     public void Dispose() | ||||
|     { | ||||
|         this.MessageBus.Unregister(this); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
| } | ||||
| @ -3,11 +3,11 @@ | ||||
|     <MudTooltip Text="Shows and hides the confidence card with information about the selected LLM provider."> | ||||
|         @if (this.Mode is ConfidenceInfoMode.ICON) | ||||
|         { | ||||
|             <MudIconButton Icon="@Icons.Material.Filled.Security" Class="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle()" OnClick="@(() => this.ToggleConfidence())"/> | ||||
|             <MudIconButton Icon="@Icons.Material.Filled.Security" Class="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager)" OnClick="@(() => this.ToggleConfidence())"/> | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             <MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Security" IconClass="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle()" OnClick="@(() => this.ToggleConfidence())"> | ||||
|             <MudButton Variant="Variant.Filled" StartIcon="@Icons.Material.Filled.Security" IconClass="confidence-icon" Style="@this.LLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager)" OnClick="@(() => this.ToggleConfidence())"> | ||||
|                 Confidence | ||||
|             </MudButton> | ||||
|         } | ||||
|  | ||||
| @ -5,7 +5,7 @@ using Microsoft.AspNetCore.Components; | ||||
| 
 | ||||
| namespace AIStudio.Components; | ||||
| 
 | ||||
| public partial class ConfidenceInfo : ComponentBase | ||||
| public partial class ConfidenceInfo : ComponentBase, IMessageBusReceiver, IDisposable | ||||
| { | ||||
|     [Parameter] | ||||
|     public ConfidenceInfoMode Mode { get; set; } = ConfidenceInfoMode.BUTTON; | ||||
| @ -16,6 +16,9 @@ public partial class ConfidenceInfo : ComponentBase | ||||
|     [Inject] | ||||
|     private SettingsManager SettingsManager { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private MessageBus MessageBus { get; init; } = null!; | ||||
| 
 | ||||
|     private Confidence currentConfidence; | ||||
|     private bool showConfidence; | ||||
| 
 | ||||
| @ -28,6 +31,9 @@ public partial class ConfidenceInfo : ComponentBase | ||||
| 
 | ||||
|     protected override async Task OnParametersSetAsync() | ||||
|     { | ||||
|         this.MessageBus.RegisterComponent(this); | ||||
|         this.MessageBus.ApplyFilters(this, [], [ Event.COLOR_THEME_CHANGED ]); | ||||
|          | ||||
|         this.currentConfidence = this.LLMProvider.GetConfidence(this.SettingsManager); | ||||
|         await base.OnParametersSetAsync(); | ||||
|     } | ||||
| @ -51,7 +57,38 @@ public partial class ConfidenceInfo : ComponentBase | ||||
|             yield return ($"Source {++index}", source); | ||||
|     } | ||||
| 
 | ||||
|     private string GetCurrentConfidenceColor() => $"color: {this.currentConfidence.Level.GetColor()};"; | ||||
|     private string GetCurrentConfidenceColor() => $"color: {this.currentConfidence.Level.GetColor(this.SettingsManager)};"; | ||||
|      | ||||
|     private string GetPopoverStyle() => $"border-color: {this.currentConfidence.Level.GetColor()}; max-width: calc(35vw);"; | ||||
|     private string GetPopoverStyle() => $"border-color: {this.currentConfidence.Level.GetColor(this.SettingsManager)}; max-width: calc(35vw);"; | ||||
|      | ||||
|     #region Implementation of IMessageBusReceiver | ||||
| 
 | ||||
|     public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|             case Event.COLOR_THEME_CHANGED: | ||||
|                 this.showConfidence = false; | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|         } | ||||
|          | ||||
|         return Task.CompletedTask; | ||||
|     } | ||||
| 
 | ||||
|     public Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data) | ||||
|     { | ||||
|         return Task.FromResult<TResult?>(default); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
|      | ||||
|     #region Implementation of IDisposable | ||||
| 
 | ||||
|     public void Dispose() | ||||
|     { | ||||
|         this.MessageBus.Unregister(this); | ||||
|     } | ||||
| 
 | ||||
|     #endregion | ||||
| } | ||||
| @ -43,7 +43,7 @@ public partial class InnerScrolling : MSGComponentBase | ||||
| 
 | ||||
|     #region Overrides of MSGComponentBase | ||||
| 
 | ||||
|     public override Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default | ||||
|     public override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|  | ||||
| @ -19,7 +19,22 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus | ||||
| 
 | ||||
|     #region Implementation of IMessageBusReceiver | ||||
| 
 | ||||
|     public abstract Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data); | ||||
|     public Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|             case Event.COLOR_THEME_CHANGED: | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|              | ||||
|             default: | ||||
|                 return this.ProcessIncomingMessage(sendingComponent, triggeredEvent, data); | ||||
|         } | ||||
|          | ||||
|         return Task.CompletedTask; | ||||
|     } | ||||
|      | ||||
|     public abstract Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data); | ||||
|      | ||||
|     public abstract Task<TResult?> ProcessMessageWithResult<TPayload, TResult>(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data); | ||||
| 
 | ||||
| @ -46,6 +61,12 @@ public abstract class MSGComponentBase : ComponentBase, IDisposable, IMessageBus | ||||
|      | ||||
|     protected void ApplyFilters(ComponentBase[] components, Event[] events) | ||||
|     { | ||||
|         this.MessageBus.ApplyFilters(this, components, events); | ||||
|         // Append the color theme changed event to the list of events: | ||||
|         var eventsList = new List<Event>(events) | ||||
|         { | ||||
|             Event.COLOR_THEME_CHANGED | ||||
|         }; | ||||
|          | ||||
|         this.MessageBus.ApplyFilters(this, components, eventsList.ToArray()); | ||||
|     } | ||||
| } | ||||
| @ -11,17 +11,17 @@ | ||||
|             <MudDrawerContainer Class="mud-height-full absolute"> | ||||
|                 <MudDrawer @bind-Open="@this.navBarOpen" MiniWidth="@NAVBAR_COLLAPSED_WIDTH" Width="@NAVBAR_EXPANDED_WIDTH" Elevation="1" Fixed="@true" Variant="@DrawerVariant.Mini" OpenMiniOnHover="@(this.SettingsManager.ConfigurationData.App.NavigationBehavior is NavBehavior.EXPAND_ON_HOVER)" Color="Color.Default"> | ||||
|                     <MudNavMenu> | ||||
|                         @foreach (var navBarItem in NAV_ITEMS) | ||||
|                         @foreach (var navBarItem in this.navItems) | ||||
|                         { | ||||
|                             if (this.SettingsManager.ConfigurationData.App.NavigationBehavior is NavBehavior.NEVER_EXPAND_USE_TOOLTIPS) | ||||
|                             { | ||||
|                                 <MudTooltip Text="@navBarItem.Name" Placement="Placement.Right"> | ||||
|                                     <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink> | ||||
|                                     <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" Style="@navBarItem.SetColorStyle(this.SettingsManager)" Class="custom-icon-color">@navBarItem.Name</MudNavLink> | ||||
|                                 </MudTooltip> | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" IconColor="@navBarItem.IconColor">@navBarItem.Name</MudNavLink> | ||||
|                                 <MudNavLink Href="@navBarItem.Path" Match="@(navBarItem.MatchAll ? NavLinkMatch.All : NavLinkMatch.Prefix)" Icon="@navBarItem.Icon" Style="@navBarItem.SetColorStyle(this.SettingsManager)" Class="custom-icon-color">@navBarItem.Name</MudNavLink> | ||||
|                             } | ||||
|                         } | ||||
|                     </MudNavMenu> | ||||
| @ -59,3 +59,5 @@ | ||||
|         </MudMainContent> | ||||
|     </MudLayout> | ||||
| </MudPaper> | ||||
| 
 | ||||
| <MudThemeProvider @ref="@this.themeProvider" Theme="@this.ColorTheme" IsDarkMode="@this.useDarkMode" /> | ||||
| @ -35,6 +35,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|     [Inject] | ||||
|     private ILogger<MainLayout> Logger { get; init; } = null!; | ||||
|      | ||||
|     [Inject] | ||||
|     private MudTheme ColorTheme { get; init; } = null!; | ||||
| 
 | ||||
|     public string AdditionalHeight { get; private set; } = "0em"; | ||||
|      | ||||
|     private string PaddingLeft => this.navBarOpen ? $"padding-left: {NAVBAR_EXPANDED_WIDTH_INT - NAVBAR_COLLAPSED_WIDTH_INT}em;" : "padding-left: 0em;"; | ||||
| @ -50,16 +53,10 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|     private bool userDismissedUpdate; | ||||
|     private string updateToVersion = string.Empty; | ||||
|     private UpdateResponse? currentUpdateResponse; | ||||
|     private MudThemeProvider themeProvider = null!; | ||||
|     private bool useDarkMode; | ||||
| 
 | ||||
|     private static readonly IReadOnlyCollection<NavBarItem> NAV_ITEMS = new List<NavBarItem> | ||||
|     { | ||||
|         new("Home", Icons.Material.Filled.Home, Color.Default, Routes.HOME, true), | ||||
|         new("Chat", Icons.Material.Filled.Chat, Color.Default, Routes.CHAT, false), | ||||
|         new("Assistants", Icons.Material.Filled.Apps, Color.Default, Routes.ASSISTANTS, false), | ||||
|         new("Supporters", Icons.Material.Filled.Favorite, Color.Error, Routes.SUPPORTERS, false), | ||||
|         new("About", Icons.Material.Filled.Info, Color.Default, Routes.ABOUT, false), | ||||
|         new("Settings", Icons.Material.Filled.Settings, Color.Default, Routes.SETTINGS, false), | ||||
|     }; | ||||
|     private IReadOnlyCollection<NavBarItem> navItems = []; | ||||
|      | ||||
|     #region Overrides of ComponentBase | ||||
| 
 | ||||
| @ -87,7 +84,7 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|          | ||||
|         // Register this component with the message bus: | ||||
|         this.MessageBus.RegisterComponent(this); | ||||
|         this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED ]); | ||||
|         this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.USER_SEARCH_FOR_UPDATE, Event.CONFIGURATION_CHANGED, Event.COLOR_THEME_CHANGED ]); | ||||
|          | ||||
|         // Set the snackbar for the update service: | ||||
|         UpdateService.SetBlazorDependencies(this.Snackbar); | ||||
| @ -97,6 +94,20 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|         if(this.SettingsManager.ConfigurationData.App.NavigationBehavior is NavBehavior.ALWAYS_EXPAND) | ||||
|             this.navBarOpen = true; | ||||
| 
 | ||||
|         await this.themeProvider.WatchSystemPreference(this.SystemeThemeChanged); | ||||
|         await this.UpdateThemeConfiguration(); | ||||
|          | ||||
|         var palette = this.ColorTheme.GetCurrentPalette(this.SettingsManager); | ||||
|         this.navItems = new List<NavBarItem> | ||||
|         { | ||||
|             new("Home", Icons.Material.Filled.Home, palette.DarkLighten, palette.GrayLight, Routes.HOME, true), | ||||
|             new("Chat", Icons.Material.Filled.Chat, palette.DarkLighten, palette.GrayLight, Routes.CHAT, false), | ||||
|             new("Assistants", Icons.Material.Filled.Apps, palette.DarkLighten, palette.GrayLight, Routes.ASSISTANTS, false), | ||||
|             new("Supporters", Icons.Material.Filled.Favorite, palette.Error.Value, "#801a00", Routes.SUPPORTERS, false), | ||||
|             new("About", Icons.Material.Filled.Info, palette.DarkLighten, palette.GrayLight, Routes.ABOUT, false), | ||||
|             new("Settings", Icons.Material.Filled.Settings, palette.DarkLighten, palette.GrayLight, Routes.SETTINGS, false), | ||||
|         }; | ||||
|          | ||||
|         await base.OnInitializedAsync(); | ||||
|     } | ||||
| 
 | ||||
| @ -131,6 +142,11 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|                 else | ||||
|                     this.navBarOpen = false; | ||||
|                  | ||||
|                 await this.UpdateThemeConfiguration(); | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|              | ||||
|             case Event.COLOR_THEME_CHANGED: | ||||
|                 this.StateHasChanged(); | ||||
|                 break; | ||||
|         } | ||||
| @ -218,6 +234,24 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private async Task SystemeThemeChanged(bool isDark) | ||||
|     { | ||||
|         this.Logger.LogInformation($"The system theme changed to {(isDark ? "dark" : "light")}."); | ||||
|         await this.UpdateThemeConfiguration(); | ||||
|     } | ||||
| 
 | ||||
|     private async Task UpdateThemeConfiguration() | ||||
|     { | ||||
|         if (this.SettingsManager.ConfigurationData.App.PreferredTheme is Themes.SYSTEM) | ||||
|             this.useDarkMode = await this.themeProvider.GetSystemPreference(); | ||||
|         else | ||||
|             this.useDarkMode = this.SettingsManager.ConfigurationData.App.PreferredTheme == Themes.DARK; | ||||
| 
 | ||||
|         this.SettingsManager.IsDarkMode = this.useDarkMode; | ||||
|         await this.MessageBus.SendMessage<bool>(this, Event.COLOR_THEME_CHANGED); | ||||
|         this.StateHasChanged(); | ||||
|     } | ||||
| 
 | ||||
|     #region Implementation of IDisposable | ||||
| 
 | ||||
|     public void Dispose() | ||||
|  | ||||
| @ -1,3 +1,8 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| namespace AIStudio.Layout; | ||||
| 
 | ||||
| public record NavBarItem(string Name, string Icon, Color IconColor, string Path, bool MatchAll); | ||||
| public record NavBarItem(string Name, string Icon, string IconLightColor, string IconDarkColor, string Path, bool MatchAll) | ||||
| { | ||||
|     public string SetColorStyle(SettingsManager settingsManager) => $"--custom-icon-color: {(settingsManager.IsDarkMode ? this.IconDarkColor : this.IconLightColor)};"; | ||||
| } | ||||
| @ -120,7 +120,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable | ||||
| 
 | ||||
|     private string TooltipAddChatToWorkspace => $"Start new chat in workspace \"{this.currentWorkspaceName}\""; | ||||
| 
 | ||||
|     private string UserInputStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).SetColorStyle() : string.Empty; | ||||
|     private string UserInputStyle => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).SetColorStyle(this.SettingsManager) : string.Empty; | ||||
|      | ||||
|     private string UserInputClass => this.SettingsManager.ConfigurationData.LLMProviders.ShowProviderConfidence ? "confidence-border" : string.Empty; | ||||
| 
 | ||||
| @ -455,7 +455,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable | ||||
| 
 | ||||
|     #region Overrides of MSGComponentBase | ||||
| 
 | ||||
|     public override Task ProcessMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default | ||||
|     public override Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default | ||||
|     { | ||||
|         switch (triggeredEvent) | ||||
|         { | ||||
|  | ||||
| @ -180,6 +180,7 @@ | ||||
|         </ExpansionPanel> | ||||
| 
 | ||||
|         <ExpansionPanel HeaderIcon="@Icons.Material.Filled.Apps" HeaderText="App Options"> | ||||
|             <ConfigurationSelect OptionDescription="Color theme" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.PreferredTheme)" Data="@ConfigurationSelectDataFactory.GetThemesData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.PreferredTheme = selectedValue)" OptionHelp="Choose the color theme that best suits for you."/> | ||||
|             <ConfigurationOption OptionDescription="Save energy?" LabelOn="Energy saving is enabled" LabelOff="Energy saving is disabled" State="@(() => this.SettingsManager.ConfigurationData.App.IsSavingEnergy)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.IsSavingEnergy = updatedState)" OptionHelp="When enabled, streamed content from the AI is updated once every third second. When disabled, streamed content will be updated as soon as it is available."/> | ||||
|             <ConfigurationOption OptionDescription="Enable spellchecking?" LabelOn="Spellchecking is enabled" LabelOff="Spellchecking is disabled" State="@(() => this.SettingsManager.ConfigurationData.App.EnableSpellchecking)" StateUpdate="@(updatedState => this.SettingsManager.ConfigurationData.App.EnableSpellchecking = updatedState)" OptionHelp="When enabled, spellchecking will be active in all input fields. Depending on your operating system, errors may not be visually highlighted, but right-clicking may still offer possible corrections." /> | ||||
|             <ConfigurationSelect OptionDescription="Check for updates" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.UpdateBehavior)" Data="@ConfigurationSelectDataFactory.GetUpdateBehaviorData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.UpdateBehavior = selectedValue)" OptionHelp="How often should we check for app updates?"/> | ||||
|  | ||||
| @ -171,9 +171,9 @@ public partial class Settings : ComponentBase, IMessageBusReceiver, IDisposable | ||||
|     private string SetCurrentConfidenceLevelColorStyle(LLMProviders llmProvider) | ||||
|     { | ||||
|         if (this.SettingsManager.ConfigurationData.LLMProviders.CustomConfidenceScheme.TryGetValue(llmProvider, out var level)) | ||||
|             return $"background-color: {level.GetColor()};"; | ||||
|             return $"background-color: {level.GetColor(this.SettingsManager)};"; | ||||
| 
 | ||||
|         return $"background-color: {ConfidenceLevel.UNKNOWN.GetColor()};"; | ||||
|         return $"background-color: {ConfidenceLevel.UNKNOWN.GetColor(this.SettingsManager)};"; | ||||
|     } | ||||
| 
 | ||||
|     private async Task ChangeCustomConfidenceLevel(LLMProviders llmProvider, ConfidenceLevel level) | ||||
|  | ||||
| @ -106,6 +106,7 @@ internal sealed class Program | ||||
|         }); | ||||
| 
 | ||||
|         builder.Services.AddMudMarkdownServices(); | ||||
|         builder.Services.AddSingleton(new MudTheme()); | ||||
|         builder.Services.AddSingleton(MessageBus.INSTANCE); | ||||
|         builder.Services.AddSingleton(rust); | ||||
|         builder.Services.AddMudMarkdownClipboardService<MarkdownClipboardService>(); | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| namespace AIStudio.Provider; | ||||
| 
 | ||||
| public sealed record Confidence | ||||
| @ -20,9 +22,9 @@ public sealed record Confidence | ||||
|      | ||||
|     public Confidence WithLevel(ConfidenceLevel level) => this with { Level = level }; | ||||
|      | ||||
|     public string StyleBorder() => $"border: 2px solid {this.Level.GetColor()}; border-radius: 6px;"; | ||||
|     public string StyleBorder(SettingsManager settingsManager) => $"border: 2px solid {this.Level.GetColor(settingsManager)}; border-radius: 6px;"; | ||||
|      | ||||
|     public string SetColorStyle() => $"--confidence-color: {this.Level.GetColor()};"; | ||||
|     public string SetColorStyle(SettingsManager settingsManager) => $"--confidence-color: {this.Level.GetColor(settingsManager)};"; | ||||
| 
 | ||||
|     public static readonly Confidence NONE = new() | ||||
|     { | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| namespace AIStudio.Provider; | ||||
| 
 | ||||
| public static class ConfidenceLevelExtensions | ||||
| @ -16,19 +18,31 @@ public static class ConfidenceLevelExtensions | ||||
|         _ => "Unknown confidence level", | ||||
|     }; | ||||
|      | ||||
|     public static string GetColor(this ConfidenceLevel level) => level switch | ||||
|     public static string GetColor(this ConfidenceLevel level, SettingsManager settingsManager) => (level, settingsManager.IsDarkMode) switch | ||||
|     { | ||||
|         ConfidenceLevel.NONE => "#cccccc", | ||||
|         (ConfidenceLevel.NONE, _) => "#cccccc", | ||||
|          | ||||
|         ConfidenceLevel.UNTRUSTED => "#ff0000", | ||||
|         ConfidenceLevel.VERY_LOW => "#ff6600", | ||||
|         ConfidenceLevel.LOW => "#ffcc00", | ||||
|         ConfidenceLevel.MODERATE => "#99cc00", | ||||
|         ConfidenceLevel.MEDIUM => "#86b300", | ||||
|         ConfidenceLevel.HIGH => "#009933", | ||||
|         (ConfidenceLevel.UNTRUSTED, false) => "#ff0000", | ||||
|         (ConfidenceLevel.UNTRUSTED, true) => "#800000", | ||||
|          | ||||
|         _ => "#cc6600", | ||||
|         (ConfidenceLevel.VERY_LOW, false) => "#ff6600", | ||||
|         (ConfidenceLevel.VERY_LOW, true) => "#803300", | ||||
|          | ||||
|         (ConfidenceLevel.LOW, false) => "#ffcc00", | ||||
|         (ConfidenceLevel.LOW, true) => "#806600", | ||||
|          | ||||
|         (ConfidenceLevel.MODERATE, false) => "#99cc00", | ||||
|         (ConfidenceLevel.MODERATE, true) => "#4d6600", | ||||
|          | ||||
|         (ConfidenceLevel.MEDIUM, false) => "#86b300", | ||||
|         (ConfidenceLevel.MEDIUM, true) => "#394d00", | ||||
|          | ||||
|         (ConfidenceLevel.HIGH, false) => "#009933", | ||||
|         (ConfidenceLevel.HIGH, true) => "#004d1a", | ||||
|          | ||||
|         (_, false) => "#cc6600", | ||||
|         (_, true) => "#663300", | ||||
|     }; | ||||
|      | ||||
|     public static string SetColorStyle(this ConfidenceLevel level) => $"--confidence-color: {level.GetColor()};"; | ||||
|     public static string SetColorStyle(this ConfidenceLevel level, SettingsManager settingsManager) => $"--confidence-color: {level.GetColor(settingsManager)};"; | ||||
| } | ||||
| @ -8,7 +8,6 @@ | ||||
|     </Found> | ||||
| </Router> | ||||
| 
 | ||||
| <MudThemeProvider /> | ||||
| <MudDialogProvider /> | ||||
| <MudPopoverProvider /> | ||||
| <MudSnackbarProvider /> | ||||
| @ -170,4 +170,10 @@ public static class ConfigurationSelectDataFactory | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static IEnumerable<ConfigurationSelectData<Themes>> GetThemesData() | ||||
|     { | ||||
|         foreach (var theme in Enum.GetValues<Themes>()) | ||||
|             yield return new(theme.GetName(), theme); | ||||
|     } | ||||
| } | ||||
| @ -2,6 +2,11 @@ namespace AIStudio.Settings.DataModel; | ||||
| 
 | ||||
| public sealed class DataApp | ||||
| { | ||||
|     /// <summary> | ||||
|     /// The preferred theme to use. | ||||
|     /// </summary> | ||||
|     public Themes PreferredTheme { get; set; } = Themes.SYSTEM; | ||||
|      | ||||
|     /// <summary> | ||||
|     /// Should we save energy? When true, we will update content streamed | ||||
|     /// from the server, i.e., AI, less frequently. | ||||
|  | ||||
							
								
								
									
										8
									
								
								app/MindWork AI Studio/Settings/DataModel/Themes.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								app/MindWork AI Studio/Settings/DataModel/Themes.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| namespace AIStudio.Settings.DataModel; | ||||
| 
 | ||||
| public enum Themes | ||||
| { | ||||
|     SYSTEM = 0, | ||||
|     LIGHT, | ||||
|     DARK, | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| namespace AIStudio.Settings.DataModel; | ||||
| 
 | ||||
| public static class ThemesExtensions | ||||
| { | ||||
|     public static string GetName(this Themes theme) | ||||
|     { | ||||
|         return theme switch | ||||
|         { | ||||
|             Themes.SYSTEM => "Synchronized with the operating system settings", | ||||
|             Themes.LIGHT => "Always use light theme", | ||||
|             Themes.DARK => "Always use dark theme", | ||||
|              | ||||
|             _ => "Unknown setting", | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @ -21,7 +21,7 @@ public sealed class SettingsManager(ILogger<SettingsManager> logger) | ||||
|         Converters = { new JsonStringEnumConverter() }, | ||||
|     }; | ||||
| 
 | ||||
|     private ILogger<SettingsManager> logger = logger; | ||||
|     private readonly ILogger<SettingsManager> logger = logger; | ||||
|      | ||||
|     /// <summary> | ||||
|     /// The directory where the configuration files are stored. | ||||
| @ -33,6 +33,11 @@ public sealed class SettingsManager(ILogger<SettingsManager> logger) | ||||
|     /// </summary> | ||||
|     public static string? DataDirectory { get; set; } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// Whether the app is in dark mode. | ||||
|     /// </summary> | ||||
|     public bool IsDarkMode { get; set; } | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// The configuration data. | ||||
|     /// </summary> | ||||
|  | ||||
| @ -7,6 +7,7 @@ public enum Event | ||||
|     // Common events: | ||||
|     STATE_HAS_CHANGED, | ||||
|     CONFIGURATION_CHANGED, | ||||
|     COLOR_THEME_CHANGED, | ||||
|      | ||||
|     // Update events: | ||||
|     USER_SEARCH_FOR_UPDATE, | ||||
|  | ||||
							
								
								
									
										12
									
								
								app/MindWork AI Studio/Tools/MudThemeExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/MindWork AI Studio/Tools/MudThemeExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| using AIStudio.Settings; | ||||
| 
 | ||||
| namespace AIStudio.Tools; | ||||
| 
 | ||||
| public static class MudThemeExtensions | ||||
| { | ||||
|     public static Palette GetCurrentPalette(this MudTheme theme, SettingsManager settingsManager) => settingsManager.IsDarkMode switch | ||||
|     { | ||||
|         true => theme.PaletteDark, | ||||
|         false => theme.PaletteLight, | ||||
|     }; | ||||
| } | ||||
| @ -47,3 +47,11 @@ | ||||
|     border-width: 2px; | ||||
|     border-color: var(--confidence-color) !important; | ||||
| } | ||||
| 
 | ||||
| :root { | ||||
|     --custom-icon-color: #000000; | ||||
| } | ||||
| 
 | ||||
| .custom-icon-color > a > svg { | ||||
|     color: var(--custom-icon-color) !important; | ||||
| } | ||||
| @ -1,5 +1,6 @@ | ||||
| # v0.9.11, build 186  | ||||
| - Added an option to enforce a minimum confidence level throughout the entire app. | ||||
| - Added options to enforce minimum confidence levels for each assistant individually. | ||||
| - Added color themes (dark & light) to the app settings. The theme can be synchronized with the system theme. | ||||
| - Added a tooltip to the confidence card button. | ||||
| - Renamed the `Providers` enum to `LLMProviders` for better clarity. Renamed also all dependent variables and methods. | ||||
							
								
								
									
										
											BIN
										
									
								
								media/Startup Icon.psd
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								media/Startup Icon.psd
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 37 KiB | 
							
								
								
									
										
											BIN
										
									
								
								runtime/ui/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								runtime/ui/icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 97 KiB | 
| @ -16,9 +16,15 @@ | ||||
|             img { | ||||
|                 display: block; | ||||
|             } | ||||
| 
 | ||||
|             @media (prefers-color-scheme: dark) { | ||||
|                 html, body { | ||||
|                     background-color: #1a1a1a; | ||||
|                 } | ||||
|             } | ||||
|         </style> | ||||
|     </head> | ||||
|     <body> | ||||
|         <img src="icon.jpg" width="512px" height="512px" alt="The app logo"> | ||||
|         <img src="icon.png" width="512" height="512" alt="The app logo"> | ||||
|     </body> | ||||
| </html> | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user