{"id":19140927,"url":"https://github.com/theeightbot/stellarui","last_synced_at":"2025-09-08T21:32:21.351Z","repository":{"id":220233538,"uuid":"497163271","full_name":"TheEightBot/StellarUI","owner":"TheEightBot","description":"Eight-Bot Client Application Core","archived":false,"fork":false,"pushed_at":"2025-07-21T21:22:45.000Z","size":809,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-04T12:54:58.577Z","etag":null,"topics":["avalonia","blazor","dotnet","maui"],"latest_commit_sha":null,"homepage":"https://eight.bot","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheEightBot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-05-27T23:24:37.000Z","updated_at":"2025-07-21T21:18:21.000Z","dependencies_parsed_at":"2024-02-01T01:25:26.861Z","dependency_job_id":"e246c7c1-3b6b-4a16-b83c-e5653914b2ec","html_url":"https://github.com/TheEightBot/StellarUI","commit_stats":null,"previous_names":["theeightbot/stellar","theeightbot/stellarui"],"tags_count":70,"template":false,"template_full_name":null,"purl":"pkg:github/TheEightBot/StellarUI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheEightBot%2FStellarUI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheEightBot%2FStellarUI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheEightBot%2FStellarUI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheEightBot%2FStellarUI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheEightBot","download_url":"https://codeload.github.com/TheEightBot/StellarUI/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheEightBot%2FStellarUI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274231461,"owners_count":25245625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avalonia","blazor","dotnet","maui"],"created_at":"2024-11-09T07:19:24.587Z","updated_at":"2025-09-08T21:32:21.339Z","avatar_url":"https://github.com/TheEightBot.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# StellarUI\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![NuGet](https://img.shields.io/nuget/v/Stellar.svg)](https://www.nuget.org/packages/StellarUI/)\n\nA comprehensive cross-platform .NET application framework built on ReactiveUI for creating reactive MVVM applications.\n\n## Overview\n\nStellarUI is a reactive UI framework that provides a structured and consistent approach to building applications across different platforms including MAUI, Blazor, and Avalonia. It implements the MVVM (Model-View-ViewModel) pattern and enhances it with reactive programming paradigms, making it easier to manage application state, handle UI events, and implement complex workflows.\n\nThe framework is designed to support multiple platforms while maintaining a consistent programming model, allowing developers to share business logic and UI patterns across different .NET UI frameworks.\n\n## Key Features\n\n- **Cross-platform support**: Build applications for MAUI (iOS, Android, Windows, macOS), Blazor (WebAssembly, Server), and Avalonia (Windows, macOS, Linux)\n- **Reactive programming model**: Built on ReactiveUI to provide robust reactive programming paradigms\n- **Consistent lifecycle management**: Standardized lifecycle events (Activated, Deactivated, IsAppearing, IsDisappearing) across all platforms\n- **Dependency injection**: First-class support for registering and resolving services with the `ServiceRegistrationAttribute`\n- **Hot reload support**: Enhanced development experience with built-in hot reload capabilities\n- **View infrastructure**: Base classes for all view types with consistent patterns for setup and binding\n- **Navigation abstractions**: Platform-agnostic navigation APIs to simplify cross-platform navigation\n- **Data binding**: Reactive two-way data binding with support for validation\n- **Popup and modal support**: Unified APIs for displaying popups and modals across platforms\n\n## Project Structure\n\nStellarUI is composed of several projects, each serving a specific purpose in the framework:\n\n### Core Libraries\n\n- **Stellar**: Core library containing shared interfaces, base classes, and utilities used by all platform implementations\n- **Stellar.Maui**: Implementation for .NET MAUI platform, providing base classes for MAUI UI components\n- **Stellar.Blazor**: Implementation for Blazor WebAssembly and Server, enabling reactive UI for web applications\n- **Stellar.Avalonia**: Implementation for Avalonia UI, supporting desktop applications on Windows, macOS, and Linux\n\n### Extensions and Utilities\n\n- **Stellar.Maui.PopUp**: Extended popup functionality for MAUI applications\n- **Stellar.FluentValidation**: Integration with FluentValidation for input validation across platforms\n- **Stellar.DiskDataCache**: Disk-based caching implementation for persistent storage\n\n### Samples\n\n- **Stellar.MauiSample**: Example application demonstrating MAUI features\n- **Stellar.BlazorSample**: Example application demonstrating Blazor features\n- **Stellar.AvaloniaSample**: Example application demonstrating Avalonia features\n- **Stellar.MauiBlazorHybridSample**: Example application demonstrating hybrid MAUI Blazor approach\n\n## Getting Started\n\n### Prerequisites\n\n- .NET 6.0 or later\n- For MAUI development: .NET MAUI workload installed\n- For Blazor development: ASP.NET Core Blazor workload installed\n- For Avalonia development: Avalonia UI dependencies\n\n### Installation\n\nTo use StellarUI in your project, add the relevant package references:\n\n```xml\n\u003c!-- For MAUI applications --\u003e\n\u003cPackageReference Include=\"Stellar\" Version=\"latest\" /\u003e\n\u003cPackageReference Include=\"Stellar.Maui\" Version=\"latest\" /\u003e\n\n\u003c!-- For Blazor applications --\u003e\n\u003cPackageReference Include=\"Stellar\" Version=\"latest\" /\u003e\n\u003cPackageReference Include=\"Stellar.Blazor\" Version=\"latest\" /\u003e\n\n\u003c!-- For Avalonia applications --\u003e\n\u003cPackageReference Include=\"Stellar\" Version=\"latest\" /\u003e\n\u003cPackageReference Include=\"Stellar.Avalonia\" Version=\"latest\" /\u003e\n```\n\n### Basic Setup\n\nStellarUI simplifies application setup across all platforms with a focus on minimizing boilerplate code. Just add these two key method calls to your existing app setup:\n\n#### MAUI Application Setup\n\n```csharp\n// In your MauiProgram.cs\npublic static MauiApp CreateMauiApp()\n{\n    var builder = MauiApp.CreateBuilder();\n    builder\n        .UseMauiApp\u003cApp\u003e()\n        // Just add these two lines to enable StellarUI:\n        .UseStellarComponents\u003cApp\u003e() // Register all StellarUI components automatically\n        .EnableHotReload();          // Enable hot reload capability (optional but recommended)\n    \n    return builder.Build();\n}\n```\n\n#### Blazor Application Setup\n\n```csharp\n// In your Program.cs\nvar builder = WebAssemblyHostBuilder.CreateDefault(args);\nbuilder.RootComponents.Add\u003cApp\u003e(\"#app\");\n\n// Just add this line to enable StellarUI:\nbuilder.Services.UseStellarComponents\u003cApp\u003e(); // Register all StellarUI components automatically\n\nawait builder.Build().RunAsync();\n```\n\n#### Avalonia Application Setup\n\n```csharp\n// In your Program.cs\npublic static AppBuilder BuildAvaloniaApp() =\u003e\n    AppBuilder.Configure\u003cApp\u003e()\n        .UsePlatformDetect()\n        // Just add these two lines to enable StellarUI:\n        .UseStellarComponents\u003cApp\u003e() // Register all StellarUI components automatically\n        .EnableHotReload()           // Enable hot reload capability (optional but recommended)\n        .UseReactiveUI();\n```\n\nThat's it! The `UseStellarComponents\u003cApp\u003e()` method handles all the necessary registration of services, views, and view models. The framework auto-discovers and registers all classes in your application that have the `[ServiceRegistration]` attribute.\n\n## Core Concepts\n\n### Base Classes and Views\n\nStellarUI provides base classes for each type of view component across platforms:\n\n#### MAUI Base Classes\n\n- `ContentPageBase\u003cTViewModel\u003e`: Base class for MAUI ContentPage\n- `GridBase\u003cTViewModel\u003e`: Base class for MAUI Grid\n- `StackLayoutBase\u003cTViewModel\u003e`: Base class for MAUI StackLayout  \n- `ContentViewBase\u003cTViewModel\u003e`: Base class for MAUI ContentView\n- `ShellBase\u003cTViewModel\u003e`: Base class for MAUI Shell\n- `PopupPageBase\u003cTViewModel\u003e`: Base class for popup pages\n\n#### Blazor Base Classes\n\n- `ComponentBase\u003cTViewModel\u003e`: Base class for Blazor components\n- `LayoutComponentBase\u003cTViewModel\u003e`: Base class for Blazor layouts\n- `InjectableComponentBase\u003cTViewModel\u003e`: Base class for components with DI\n\n#### Avalonia Base Classes\n\n- `WindowBase\u003cTViewModel\u003e`: Base class for Avalonia windows\n- `UserControlBase\u003cTViewModel\u003e`: Base class for Avalonia user controls\n\n### View Implementation Pattern\n\nAll views follow a consistent pattern for setup and binding:\n\n```csharp\n[ServiceRegistration] // Optional: Register for dependency injection\npublic class SampleView : ContentViewBase\u003cSampleViewModel\u003e\n{\n    private Label _label;\n    \n    // Constructor - initialize with the view model\n    public SampleView(SampleViewModel viewModel)\n    {\n        this.InitializeStellarComponent(viewModel);\n    }\n    \n    // Setup the UI elements\n    public override void SetupUserInterface()\n    {\n        Content = new Label()\n            .Assign(out _label);\n    }\n    \n    // Bind the UI elements to the view model\n    public override void Bind(WeakCompositeDisposable disposables)\n    {\n        this.OneWayBind(ViewModel, vm =\u003e vm.Text, v =\u003e v._label.Text)\n            .DisposeWith(disposables);\n            \n        // Add other bindings as needed\n    }\n}\n```\n\n### ViewModels\n\nViewModels in StellarUI inherit from `ViewModelBase` and use the `[Reactive]` attribute from ReactiveUI for reactive properties:\n\n```csharp\n[ServiceRegistration] // Register for dependency injection\npublic partial class SampleViewModel : ViewModelBase\n{\n    [Reactive]\n    public string Text { get; set; } = \"Hello, World!\";\n    \n    // Initialize method for setup that happens at creation time\n    protected override void Initialize()\n    {\n        // Setup initial values, etc.\n    }\n    \n    // Bind method for setting up reactive bindings\n    protected override void Bind(WeakCompositeDisposable disposables)\n    {\n        // Setup observables, commands, etc.\n        this.WhenAnyValue(x =\u003e x.Text)\n            .Subscribe(text =\u003e Console.WriteLine($\"Text changed: {text}\"))\n            .DisposeWith(disposables);\n    }\n}\n```\n\n### Dependency Injection\n\nStellarUI provides a `ServiceRegistrationAttribute` to automatically register classes with the dependency injection system:\n\n```csharp\n// Register as transient (default)\n[ServiceRegistration]\npublic class TransientService : IService { }\n\n// Register as singleton\n[ServiceRegistration(Lifetime.Singleton)]\npublic class SingletonService : IService { }\n\n// Register as scoped\n[ServiceRegistration(Lifetime.Scoped)]\npublic class ScopedService : IService { }\n```\n\nServices can be injected into ViewModels through constructor injection:\n\n```csharp\n[ServiceRegistration]\npublic partial class SampleViewModel : ViewModelBase\n{\n    private readonly IService _service;\n    \n    // Constructor injection\n    public SampleViewModel(IService service)\n    {\n        _service = service;\n    }\n    \n    // Rest of the ViewModel...\n}\n```\n\n\n#### Compile-Time Service Registration with Source Generator\n\nStellarUI includes a Roslyn source generator that emits a strongly-typed registration extension based on your assembly, eliminating runtime reflection.\n\n1. Add the generator package to your project via NuGet:\n\n    ```bash\n    dotnet add package StellarUI.SourceGenerators --version \u003clatest-version\u003e\n    ```\n\n2. Rebuild your project to produce `AddRegisteredServicesFor{YourAssemblyName}.g.cs` in `obj/\u003cTFM\u003e/generated`.\n\n3. In your startup code (e.g., `MauiProgram.cs` or `Program.cs`), call the generated extension:\n\n    ```csharp\n    using Stellar; // namespace of generated code\n    \n    builder.Services.AddRegisteredServicesForMyApp(); // replace MyApp with your project's AssemblyName\n    ```\n\nAll `[ServiceRegistration]` attributed types will be registered at compile time.\n\n### Lifecycle Management\n\nStellarUI provides a consistent set of lifecycle events across all platforms:\n\n- **Initialized**: Called when the view is first initialized\n- **Activated**: Called when the view is activated\n- **Deactivated**: Called when the view is deactivated\n- **IsAppearing**: Called when the view is appearing on screen\n- **IsDisappearing**: Called when the view is disappearing from screen\n- **Disposed**: Called when the view is being disposed\n\nThese events are exposed as `IObservable\u003cUnit\u003e` properties on all view base classes, allowing you to react to them with reactive extensions:\n\n```csharp\npublic class SampleView : ContentViewBase\u003cSampleViewModel\u003e\n{\n    public SampleView(SampleViewModel viewModel)\n    {\n        this.InitializeStellarComponent(viewModel);\n        \n        // Subscribe to lifecycle events\n        this.IsAppearing\n            .Subscribe(_ =\u003e Console.WriteLine(\"View is appearing\"))\n            .DisposeWith(disposables);\n            \n        this.IsDisappearing\n            .Subscribe(_ =\u003e Console.WriteLine(\"View is disappearing\"))\n            .DisposeWith(disposables);\n    }\n    \n    // Rest of the view...\n}\n```\n\nViewModels can implement the `ILifecycleEventAware` interface to be notified of lifecycle events:\n\n```csharp\n[ServiceRegistration]\npublic partial class SampleViewModel : ViewModelBase, ILifecycleEventAware\n{\n    public void OnLifecycleEvent(LifecycleEvent lifecycleEvent)\n    {\n        switch (lifecycleEvent)\n        {\n            case LifecycleEvent.IsAppearing:\n                // Handle appearing\n                break;\n            case LifecycleEvent.IsDisappearing:\n                // Handle disappearing\n                break;\n            // Handle other lifecycle events...\n        }\n    }\n    \n    // Rest of the ViewModel...\n}\n```\n\n### Navigation\n\nStellarUI provides platform-agnostic navigation abstractions to simplify navigation across different platforms:\n\n#### MAUI Navigation\n\n```csharp\n// Navigate to a page\nObservable.Return(Unit.Default)\n    .NavigateToPage\u003cSimpleSamplePage\u003e(this)\n    .DisposeWith(disposables);\n\n// Navigate to a page with parameters\nObservable.Return(42)  // The parameter value\n    .NavigateToPage\u003cint, ParameterizedPage\u003e(\n        this,\n        queryParameters: (value, dict) =\u003e\n        {\n            dict.Add(\"ParameterValue\", value);\n        })\n    .DisposeWith(disposables);\n\n// Show popup\nthis.BindCommand(ViewModel, vm =\u003e vm.ShowPopupCommand, v =\u003e v._popupButton)\n    .DisposeWith(disposables);\n\n// In ViewModel\n_showPopupCommand = ReactiveCommand.CreateFromTask(async () =\u003e\n{\n    await PopupNavigation.Instance.PushAsync(\n        new SamplePopupPage(new SampleViewModel()));\n});\n```\n\n#### Blazor Navigation\n\n```csharp\n// Navigate in a Blazor component\nNavigation.NavigateTo(\"/details/42\");\n\n// In the target page class, receive the parameter\n[Parameter]\npublic string Id { get; set; }\n\n// Or with query parameters\n[QueryParameter]\npublic int ParameterValue { get; set; }\n```\n\n#### Avalonia Navigation\n\n```csharp\n// Navigate in an Avalonia application\nvar window = new DetailWindow(new DetailViewModel());\nwindow.Show();\n```\n\n## Advanced Features\n\n### Validation\n\nStellarUI integrates with FluentValidation for model validation across all platforms:\n\n```csharp\n// Define a validator\npublic class UserValidator : AbstractValidator\u003cUserViewModel\u003e\n{\n    public UserValidator()\n    {\n        RuleFor(x =\u003e x.Username).NotEmpty().MinimumLength(4);\n        RuleFor(x =\u003e x.Email).NotEmpty().EmailAddress();\n        RuleFor(x =\u003e x.Age).GreaterThan(0).LessThan(120);\n    }\n}\n\n// Use the validator in a view model\n[ServiceRegistration]\npublic partial class UserViewModel : ViewModelBase, IProvideValidation\n{\n    [Reactive]\n    public string Username { get; set; }\n    \n    [Reactive]\n    public string Email { get; set; }\n    \n    [Reactive]\n    public int Age { get; set; }\n    \n    // Implementation of IProvideValidation\n    public IEnumerable\u003cValidationResult\u003e Validate()\n    {\n        var validator = new UserValidator();\n        var results = validator.Validate(this);\n        \n        return results.Errors\n            .Select(x =\u003e new ValidationResult(x.PropertyName, x.ErrorMessage));\n    }\n    \n    // Track validity in the view model\n    [Reactive]\n    public bool IsValid { get; private set; }\n    \n    protected override void Bind(CompositeDisposable disposables)\n    {\n        this.WhenAnyValue(x =\u003e x.Username, x =\u003e x.Email, x =\u003e x.Age)\n            .Throttle(TimeSpan.FromMilliseconds(300))\n            .ObserveOn(RxApp.MainThreadScheduler)\n            .Subscribe(_ =\u003e \n            {\n                IsValid = !Validate().Any();\n            })\n            .DisposeWith(disposables);\n    }\n}\n```\n\n### Data Caching\n\nThe `Stellar.DiskDataCache` package provides disk-based caching capabilities:\n\n```csharp\n// Register the cache in your DI setup\nservices.AddSingleton\u003cIDataCache, DiskCache\u003e();\n\n// Use the cache in a view model\n[ServiceRegistration]\npublic partial class CachedDataViewModel : ViewModelBase\n{\n    private readonly IDataCache _cache;\n    \n    public CachedDataViewModel(IDataCache cache)\n    {\n        _cache = cache;\n    }\n    \n    [Reactive]\n    public ObservableCollection\u003cstring\u003e Items { get; private set; }\n    \n    protected override async void Initialize()\n    {\n        // Try to load from cache first\n        var cachedItems = await _cache.GetAsync\u003cList\u003cstring\u003e\u003e(\"items\");\n        if (cachedItems != null)\n        {\n            Items = new ObservableCollection\u003cstring\u003e(cachedItems);\n        }\n        else\n        {\n            Items = new ObservableCollection\u003cstring\u003e();\n        }\n    }\n    \n    public async Task SaveItems()\n    {\n        await _cache.SetAsync(\"items\", Items.ToList());\n    }\n}\n```\n\n### Hot Reload\n\nStellarUI has built-in support for hot reload during development:\n\n```csharp\n// Enable hot reload in a MAUI app\nbuilder.EnableHotReload();\n\n// Enable hot reload in an Avalonia app\nAppBuilder.Configure\u003cApp\u003e()\n    // ... other configuration ...\n    .EnableHotReload()\n    .UseReactiveUI();\n```\n\n## Contributing\n\nContributions to StellarUI are welcome! Here's how you can contribute:\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feature/my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin feature/my-new-feature`\n5. Submit a pull request\n\n### Development Setup\n\n1. Clone the repository\n2. Open `Stellar.sln` in Visual Studio or your preferred IDE\n3. Build the solution\n4. Run one of the sample applications to test your changes\n\n## License\n\nStellarUI is licensed under the MIT License. See the LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheeightbot%2Fstellarui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheeightbot%2Fstellarui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheeightbot%2Fstellarui/lists"}