UI/Components/Menu/MenuWidgets.cs

UI widget definitions for the menu system. Declares an abstract base MenuWidget and many concrete widget types (links, toggles, ranges, cards, grids, lists, etc.) with properties and simple helper methods to invoke actions and navigate routes.

Networking
namespace Sunless.Libraries.UI;

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Components;
using Sandbox;

public abstract class MenuWidget
{
	public string Label { get; set; }
	public string Hint { get; set; }
}

public sealed class MenuSectionWidget : MenuWidget { }
public sealed class MenuTextWidget : MenuWidget { public string Text { get; init; } }

public sealed class MenuLinkWidget : MenuWidget
{
	public string Icon { get; set; }
	public MenuLinkStyle Style { get; set; }
	public MenuTone Tone { get; set; }
	public Action Invoke { get; set; }
	public string RouteId { get; set; }
	public Func<bool> Enabled { get; set; }
	public bool Grow { get; set; }
	public bool IsEnabled => Enabled?.Invoke() ?? true;

	public void Activate()
	{
		try { Invoke?.Invoke(); }
		catch ( Exception e ) { Log.Warning( $"[Menu] link invoke threw: {e.Message}" ); }

		if ( !string.IsNullOrEmpty( RouteId ) )
			Menu.Navigate( RouteId );
	}
}

public sealed class MenuToggleWidget : MenuWidget
{
	public Func<bool> Get { get; set; }
	public Action<bool> Set { get; set; }
}

public sealed class MenuRangeWidget : MenuWidget
{
	public Func<float> Get { get; set; }
	public Action<float> Set { get; set; }
	public float Min { get; set; }
	public float Max { get; set; }
	public float Step { get; set; }
	public string Format { get; set; }
}

public sealed class MenuSegmentedWidget : MenuWidget
{
	public string[] Choices { get; set; }
	public Func<int> Get { get; set; }
	public Action<int> Set { get; set; }
}

public sealed class MenuInfoWidget : MenuWidget
{
	public Func<string> Get { get; set; }
	public string Icon { get; set; }
}

public sealed class MenuTextFieldWidget : MenuWidget
{
	public Func<string> Get { get; set; }
	public Action<string> Set { get; set; }
}

public sealed class MenuComponentWidget : MenuWidget
{
	public RenderFragment Content { get; init; }
}

public sealed class MenuHeroCardWidget : MenuWidget
{
	public string Title { get; set; }
	public string Subtitle { get; set; }
	public string Description { get; set; }
	public string Image { get; set; }
	public string Icon { get; set; }
}

public sealed class MenuMapCardWidget : MenuWidget
{
	public string Title { get; set; }
	public string Description { get; set; }
	public string Image { get; set; }
	public string ChipLabel { get; set; }
	public string ChipIcon { get; set; }
	public MenuTone ChipTone { get; set; } = MenuTone.Confirm;
	public string ActionLabel { get; set; }
	public string ActionIcon { get; set; }
	public Action ActionInvoke { get; set; }
	public string ActionRouteId { get; set; }

	public void TriggerAction()
	{
		try { ActionInvoke?.Invoke(); }
		catch ( Exception e ) { Log.Warning( $"[Menu] map-card action threw: {e.Message}" ); }
		if ( !string.IsNullOrEmpty( ActionRouteId ) )
			Menu.Navigate( ActionRouteId );
	}
}

public sealed class MenuMapGridWidget : MenuWidget
{
	public IReadOnlyList<Card> Cards { get; set; }
	public Func<int> Active { get; set; }
	public Action<int> Pick { get; set; }

	public sealed class Card
	{
		public string Title { get; set; }
		public string Description { get; set; }
		public string Image { get; set; }
		public string BadgeLabel { get; set; }
		public MenuTone BadgeTone { get; set; } = MenuTone.Confirm;
		public bool ComingSoon { get; set; }
		public bool Locked { get; set; }
	}
}

public sealed class MenuRadioWidget : MenuWidget
{
	public IReadOnlyList<Option> Options { get; set; }
	public Func<int> Get { get; set; }
	public Action<int> Set { get; set; }

	public sealed class Option
	{
		public string Label { get; set; }
		public string Icon { get; set; }
		public string Hint { get; set; }
	}
}

public sealed class MenuTileGridWidget : MenuWidget
{
	public IReadOnlyList<Item> Items { get; set; }
	public Func<int> Active { get; set; }
	public Action<int> Pick { get; set; }

	public sealed class Item
	{
		public string Label { get; set; }
		public string Color { get; set; }
		public string Image { get; set; }
	}
}

public sealed class MenuPlayerListWidget : MenuWidget
{
	public IReadOnlyList<Player> Players { get; set; }

	public sealed class Player
	{
		public string Name { get; set; }
		public bool Ready { get; set; }
		public bool Host { get; set; }
	}
}

public sealed class MenuKeyBindingsWidget : MenuWidget
{
	public IReadOnlyList<Binding> Bindings { get; set; }

	public sealed class Binding
	{
		public string Action { get; set; }
		public string[] Keys { get; set; }
	}
}

public sealed class MenuPromptCardWidget : MenuWidget
{
	public string Verb { get; set; }
	public string Prompt { get; set; }
	public string Glyph { get; set; }
	public int Cost { get; set; }
	public Func<bool> Disabled { get; set; }
	public Func<float> Progress { get; set; }
	public bool IsDisabled => Disabled?.Invoke() ?? false;
}

public sealed class MenuActionRowWidget : MenuWidget
{
	public IReadOnlyList<MenuLinkWidget> Links { get; set; }
}