Color-coded launch configurations (Closes #1319) (#1425)

This commit is contained in:
2026-02-11 13:54:38 -08:00
parent 5447633500
commit 9f15df9b6d
7 changed files with 120 additions and 14 deletions
@@ -113,6 +113,7 @@ internal sealed class LaunchConfigurationService(
config.SteamSupport = launchConfigurationWithCredentials.SteamSupport;
config.EnabledMods = launchConfigurationWithCredentials.EnabledMods;
config.CustomModLoadoutEnabled = launchConfigurationWithCredentials.CustomModLoadoutEnabled;
config.Color = launchConfigurationWithCredentials.Color;
var options = this.liveUpdateableOptions.CurrentValue;
options.LaunchConfigurations = configs;
this.optionsProvider.SaveOption(options);
@@ -128,7 +129,8 @@ internal sealed class LaunchConfigurationService(
Arguments = launchConfigurationWithCredentials.Arguments,
SteamSupport = launchConfigurationWithCredentials.SteamSupport,
EnabledMods = launchConfigurationWithCredentials.EnabledMods,
CustomModLoadoutEnabled = launchConfigurationWithCredentials.CustomModLoadoutEnabled
CustomModLoadoutEnabled = launchConfigurationWithCredentials.CustomModLoadoutEnabled,
Color = launchConfigurationWithCredentials.Color
});
var optionsNew = this.liveUpdateableOptions.CurrentValue;
optionsNew.LaunchConfigurations = configs;
@@ -158,7 +160,8 @@ internal sealed class LaunchConfigurationService(
Name = launchConfiguration.Name,
SteamSupport = launchConfiguration.SteamSupport ?? true,
EnabledMods = launchConfiguration.EnabledMods,
CustomModLoadoutEnabled = launchConfiguration.CustomModLoadoutEnabled ?? false
CustomModLoadoutEnabled = launchConfiguration.CustomModLoadoutEnabled ?? false,
Color = launchConfiguration.Color
};
}
}
@@ -37,6 +37,27 @@
Placeholder="Custom name" />
</div>
</div>
<div class="launch-config-color">
<div class="launch-config-color-label">
<FluentLabel>Accent Color</FluentLabel>
</div>
<div class="launch-config-color-field">
<FluentSelect TOption="string" Multiple="false" Width="100%" Position="SelectPosition.Below"
Items="@this.ViewModel.AvailableColors"
SelectedOption="@(config.Color ?? string.Empty)"
SelectedOptionChanged="@((newValue) => this.ViewModel.ColorChanged(config, newValue))">
<OptionTemplate>
<div class="color-option">
@if (!string.IsNullOrWhiteSpace(context))
{
<div class="color-swatch" style="background-color: @(Daybreak.Shared.Models.ColorPalette.AccentColor.Accents.FirstOrDefault(a => a.Name.ToString() == context)?.Hex ?? "transparent")"></div>
}
<span>@this.ViewModel.GetColorDisplayName(context)</span>
</div>
</OptionTemplate>
</FluentSelect>
</div>
</div>
<div class="launch-config-executable">
<div class="launch-config-executable-label">
<FluentLabel>Executable</FluentLabel>
@@ -1,4 +1,5 @@
using Daybreak.Shared.Models;
using Daybreak.Shared.Models.ColorPalette;
using Daybreak.Shared.Models.LaunchConfigurations;
using Daybreak.Shared.Services.Credentials;
using Daybreak.Shared.Services.ExecutableManagement;
@@ -24,6 +25,7 @@ public sealed class LaunchConfigurationsViewModel(
public List<string> Executables { get; } = [];
public List<LoginCredentials> Credentials { get; } = [];
public List<LaunchConfigurationWithCredentials> LaunchConfigurations { get; } = [];
public List<string> AvailableColors { get; } = [string.Empty, .. AccentColor.Accents.Select(a => a.Name.ToString())];
public override ValueTask ParametersSet(LaunchConfigurationsView view, CancellationToken cancellationToken)
{
@@ -98,4 +100,15 @@ public sealed class LaunchConfigurationsViewModel(
{
this.viewManager.ShowView<ModsView>((nameof(ModsView.LaunchConfigurationIdentifier), configuration.Identifier ?? throw new InvalidOperationException("Managed configuration identifier cannot be null")));
}
public void ColorChanged(LaunchConfigurationWithCredentials configuration, string newColor)
{
configuration.Color = string.IsNullOrWhiteSpace(newColor) ? null : newColor;
this.launchConfigurationService.SaveConfiguration(configuration);
}
public string GetColorDisplayName(string colorName)
{
return string.IsNullOrWhiteSpace(colorName) ? "Default" : colorName;
}
}
@@ -52,7 +52,8 @@
.launch-config-name,
.launch-config-args,
.launch-config-steam,
.launch-config-custom-mods {
.launch-config-custom-mods,
.launch-config-color {
display: flex;
flex-direction: row;
width: 100%;
@@ -67,7 +68,8 @@
.launch-config-name-label,
.launch-config-args-label,
.launch-config-steam-label,
.launch-config-custom-mods-label {
.launch-config-custom-mods-label,
.launch-config-color-label {
width: 250px;
}
@@ -77,7 +79,8 @@
.launch-config-name-field,
.launch-config-args-field,
.launch-config-steam-field,
.launch-config-custom-mods-field {
.launch-config-custom-mods-field,
.launch-config-color-field {
width: 50%;
display: flex;
flex-direction: row;
@@ -87,7 +90,8 @@
/* Limit dropdown height to prevent container overflow */
.launch-config-executable-field ::deep fluent-select::part(listbox),
.launch-config-credentials-field ::deep fluent-select::part(listbox) {
.launch-config-credentials-field ::deep fluent-select::part(listbox),
.launch-config-color-field ::deep fluent-select::part(listbox) {
max-height: 150px;
overflow-y: auto;
overflow-x: hidden;
@@ -95,18 +99,21 @@
/* Scrollbar styling for the dropdown */
.launch-config-executable-field ::deep fluent-select::part(listbox)::-webkit-scrollbar,
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar {
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar,
.launch-config-color-field ::deep fluent-select::part(listbox)::-webkit-scrollbar {
width: 6px;
}
.launch-config-executable-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-track,
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-track {
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-track,
.launch-config-color-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-track {
background: color-mix(in srgb, var(--neutral-fill-rest) 30%, transparent);
border-radius: 3px;
}
.launch-config-executable-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-thumb,
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-thumb {
.launch-config-credentials-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-thumb,
.launch-config-color-field ::deep fluent-select::part(listbox)::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--neutral-fill-strong-rest) 80%, transparent);
border-radius: 3px;
}
@@ -118,7 +125,8 @@
.launch-config-name-label ::deep *,
.launch-config-args-label ::deep *,
.launch-config-steam-label ::deep *,
.launch-config-custom-mods-label ::deep * {
.launch-config-custom-mods-label ::deep *,
.launch-config-color-label ::deep * {
font-size: var(--font-size-large) !important;
}
@@ -128,7 +136,8 @@
.launch-config-name-field ::deep fluent-text-field,
.launch-config-args-field ::deep fluent-text-field,
.launch-config-steam-field ::deep fluent-text-field,
.launch-config-custom-mods-field ::deep fluent-text-field {
.launch-config-custom-mods-field ::deep fluent-text-field,
.launch-config-color-field ::deep fluent-text-field {
width: 100%;
box-sizing: border-box !important;
font-size: var(--font-size-large);
@@ -140,9 +149,26 @@
.launch-config-name-field ::deep fluent-select,
.launch-config-args-field ::deep fluent-select,
.launch-config-steam-field ::deep fluent-select,
.launch-config-custom-mods-field ::deep fluent-select {
.launch-config-custom-mods-field ::deep fluent-select,
.launch-config-color-field ::deep fluent-select {
width: 100%;
box-sizing: border-box !important;
font-size: var(--font-size-large) !important;
--type-ramp-base-font-size: var(--font-size-large);
}
/* Color option styling */
.color-option {
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
}
.color-swatch {
width: 16px;
height: 16px;
border-radius: 4px;
border: 1px solid var(--neutral-stroke-rest);
flex-shrink: 0;
}
+37 -1
View File
@@ -1,11 +1,12 @@
@inherits ViewBase<LaunchView, LaunchViewModel>
@using Daybreak.Shared.Models
@using Daybreak.Shared.Models.ColorPalette
@page "/launch"
<div class="launch-container">
<div class="launch-button-container">
<!-- Main Launch Button with Dropdown -->
<div class="launch-button-group">
<div class="launch-button-group" style="@this.GetButtonGroupStyle()">
<!-- Main Launch Button -->
<button class="launch-button @(this.ViewModel.CanLaunch ? "enabled" : "disabled")"
@onclick="this.ViewModel.LaunchSelectedConfiguration">
@@ -38,6 +39,7 @@
@foreach (var config in this.ViewModel.LaunchConfigurations.Where(c => c != this.ViewModel.SelectedConfiguration))
{
<div class="dropdown-item @(config == ViewModel.SelectedConfiguration ? "selected" : "")"
style="@this.GetDropdownItemStyle(config)"
@onclick="() => this.ViewModel.SelectConfiguration(config)">
<div class="config-info">
<div class="config-name">@(config.Configuration?.Name is null or ""
@@ -64,4 +66,38 @@
@code {
[Parameter]
public string? AutoLaunchConfigurationId { get; set; }
private string GetButtonGroupStyle()
{
var colorName = this.ViewModel.SelectedConfiguration?.Configuration?.Color;
if (string.IsNullOrWhiteSpace(colorName))
{
return string.Empty;
}
var accentColor = AccentColor.Accents.FirstOrDefault(a => a.Name.ToString() == colorName);
if (accentColor is null)
{
return string.Empty;
}
return $"background: {accentColor.Hex};";
}
private string GetDropdownItemStyle(LauncherViewContext config)
{
var colorName = config.Configuration?.Color;
if (string.IsNullOrWhiteSpace(colorName))
{
return string.Empty;
}
var accentColor = AccentColor.Accents.FirstOrDefault(a => a.Name.ToString() == colorName);
if (accentColor is null)
{
return string.Empty;
}
return $"border-left: 4px solid {accentColor.Hex};";
}
}
@@ -27,4 +27,7 @@ public sealed class LaunchConfiguration
[JsonPropertyName(nameof(CustomModLoadoutEnabled))]
public bool? CustomModLoadoutEnabled { get; set; }
[JsonPropertyName(nameof(Color))]
public string? Color { get; set; }
}
@@ -10,6 +10,7 @@ public sealed class LaunchConfigurationWithCredentials : IEquatable<LaunchConfig
public LoginCredentials? Credentials { get; set; }
public List<string>? EnabledMods { get; set; }
public bool CustomModLoadoutEnabled { get; set; }
public string? Color { get; set; }
public bool Equals(LaunchConfigurationWithCredentials? other)
{
@@ -32,7 +33,10 @@ public sealed class LaunchConfigurationWithCredentials : IEquatable<LaunchConfig
this.SteamSupport == other.SteamSupport &&
this.EnabledMods?.SequenceEqual(other.EnabledMods ?? []) is true &&
this.CustomModLoadoutEnabled == other.CustomModLoadoutEnabled;
this.CustomModLoadoutEnabled == other.CustomModLoadoutEnabled &&
((this.Color is null && other.Color is null) ||
(this.Color is not null && other.Color is not null && string.Equals(this.Color, other.Color, StringComparison.Ordinal)));
}
public override bool Equals(object? obj)