Code/Demos/AnimationShowcaseUI.cs
using Goo;
using Sandbox.AnimationShowcase;
using Sandbox.UI;
using static Sandbox.DemoTokens;

namespace Sandbox;

// Root composition for the animation showcase. The section/component pieces live in
// Code/Demo/AnimationShowcase/ and are composed here the same way Razor pages compose
// .razor pieces in addons/menu - small files imported and re-used together.
public class AnimationShowcaseUI : GooPanel<Container>
{
    readonly DampersSection      _dampers       = new();
    readonly EasingsSection      _easings       = new();
    readonly ComposersSection    _composers     = new();
    readonly FromCurveSection    _fromCurve     = new();
    readonly AnimatorSection     _animator      = new();
    readonly FadePulseSection    _fadePulse     = new();
    readonly StaggerSection      _stagger       = new();
    readonly ChoreographySection _choreography  = new();
    readonly MouseFollowSection  _follow        = new();

    int _activeTab;

    protected override void OnUpdate()
    {
        float dt = Time.Delta;
        _dampers.Update( dt );
        _easings.Update( dt );
        _animator.Update( dt );
        _fadePulse.Update( dt );
        _stagger.Update( dt );
        _choreography.Update( dt );
        _follow.Update( dt );
        Rebuild();
        base.OnUpdate();
    }

    protected override Container Build() => new Container
    {
        Padding         = Space5,
        BackgroundColor = BgBase,
        FlexDirection   = FlexDirection.Column,
        Gap             = Space4,
        AlignItems      = Align.FlexStart,
        Children =
        {
            TabBar.Build( _activeTab, idx => _activeTab = idx, "showcase", "timelines", "mouse follow" ),
            ActivePage(),
        },
    };

    Container ActivePage() => _activeTab switch
    {
        0 => ShowcasePage(),
        1 => TimelinesPage(),
        _ => FollowPage(),
    };

    // keyed page wrappers keep Children fully keyed so tab swaps unmount/mount cleanly instead of positionally diffing differently-shaped subtrees (which warns "Keyless child list changed length").
    Container ShowcasePage() => new Container
    {
        Key           = "page-showcase",
        FlexDirection = FlexDirection.Column,
        Gap           = Space5,
        AlignItems    = Align.FlexStart,
        Children =
        {
            _dampers.Build(),
            _easings.Build(),
            _composers.Build(),
            _fromCurve.Build(),
            _animator.Build(),
        },
    };

    Container TimelinesPage() => new Container
    {
        Key           = "page-timelines",
        FlexDirection = FlexDirection.Column,
        Gap           = Space5,
        AlignItems    = Align.FlexStart,
        Children =
        {
            _fadePulse.Build(),
            _stagger.Build(),
            _choreography.Build(),
        },
    };

    Container FollowPage() => new Container
    {
        Key      = "page-follow",
        Children = { _follow.Build() },
    };
}