mirror of
https://github.com/dnwSilver/tld.git
synced 2024-11-25 16:42:07 +00:00
♻️ Refactoring render engine.
This commit is contained in:
parent
5514c6bd7a
commit
dfa9d9e665
6
TLD.sln
6
TLD.sln
@ -2,6 +2,8 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI", "src\TUI\TUI.csproj", "{F92C03F7-2A65-4D0A-9736-13E749AF6903}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI", "src\TUI\TUI.csproj", "{F92C03F7-2A65-4D0A-9736-13E749AF6903}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUI.Tests", "tests\WIdgets\TUI.Tests\TUI.Tests.csproj", "{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -16,5 +18,9 @@ Global
|
|||||||
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Release|Any CPU.Build.0 = Release|Any CPU
|
{F92C03F7-2A65-4D0A-9736-13E749AF6903}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2F0611D2-073F-4E26-BD1B-ACC433FC6F4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
51
docs/RENDER.md
Normal file
51
docs/RENDER.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# RENDER
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
%% Application layer
|
||||||
|
class ViewPort{
|
||||||
|
+ GetCanvas()
|
||||||
|
+ string: Content
|
||||||
|
}
|
||||||
|
|
||||||
|
%% Хранит данные
|
||||||
|
class Store {
|
||||||
|
Reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
%% Хранит разметку
|
||||||
|
class View {
|
||||||
|
Store
|
||||||
|
SetWidgets()
|
||||||
|
SetCanvas()
|
||||||
|
Render()
|
||||||
|
}
|
||||||
|
|
||||||
|
%% Подгатавливает текст
|
||||||
|
class Painter {
|
||||||
|
+ SetGrid()
|
||||||
|
+ SetView()
|
||||||
|
}
|
||||||
|
|
||||||
|
%% Composition
|
||||||
|
class Widget {
|
||||||
|
+ State
|
||||||
|
~ Bind()
|
||||||
|
~ Render()
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetState
|
||||||
|
<<Enum>> WidgetState
|
||||||
|
WidgetState : Loading
|
||||||
|
WidgetState : Mounted
|
||||||
|
WidgetState : BindingError
|
||||||
|
WidgetState : RenderError
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Change_Store --> Binding_Widgets
|
||||||
|
Binding_Widgets --> Render_Widgets
|
||||||
|
Render_Widgets --> Create_View
|
||||||
|
Create_View --> Fill_View_Port
|
||||||
|
```
|
10
src/Dashboard/Dashboard.csproj
Normal file
10
src/Dashboard/Dashboard.csproj
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
9
src/Dashboard/Program.cs
Normal file
9
src/Dashboard/Program.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Dashboard;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello, World!");
|
||||||
|
}
|
||||||
|
}
|
37
src/TUI/Components/Controls/CellsComponentBase.cs
Normal file
37
src/TUI/Components/Controls/CellsComponentBase.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls;
|
||||||
|
|
||||||
|
public class CellsComponentBase : ComponentBase, IComponent
|
||||||
|
{
|
||||||
|
private const int MaxCellWidth = 10;
|
||||||
|
|
||||||
|
private readonly IEnumerable<string> _cells;
|
||||||
|
|
||||||
|
|
||||||
|
public CellsComponentBase(IEnumerable<string> cells)
|
||||||
|
{
|
||||||
|
_cells = cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Horizontal horizontal, Size size)
|
||||||
|
{
|
||||||
|
var content = new StringBuilder();
|
||||||
|
foreach (var cell in _cells)
|
||||||
|
{
|
||||||
|
content.Append(Symbols.Space.Repeat(MaxCellWidth - cell.Width()));
|
||||||
|
content.Append(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
// base.Render(content, position, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Content Render()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
18
src/TUI/Components/Controls/Copyright.cs
Normal file
18
src/TUI/Components/Controls/Copyright.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls;
|
||||||
|
|
||||||
|
public class Copyright : ComponentStaticBase
|
||||||
|
{
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append(Symbols.Copyright);
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.Append("Kolosov A. aka \"dnwSilver\"".Hint());
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.Append(DateTime.Now.Year);
|
||||||
|
}
|
||||||
|
}
|
68
src/TUI/Components/Controls/Dashboard.cs
Normal file
68
src/TUI/Components/Controls/Dashboard.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls;
|
||||||
|
|
||||||
|
public class Dashboard : ComponentBase, IComponent
|
||||||
|
{
|
||||||
|
private readonly string _title;
|
||||||
|
|
||||||
|
public Dashboard(string title)
|
||||||
|
{
|
||||||
|
_title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Horizontal horizontal, Size size)
|
||||||
|
{
|
||||||
|
var dashboardBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
RenderTopLine(dashboardBuilder, size, _title);
|
||||||
|
RenderMiddleLine(dashboardBuilder, size);
|
||||||
|
RenderBottomLine(dashboardBuilder, size);
|
||||||
|
|
||||||
|
// base.Render(dashboardBuilder, position, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RenderTopLine(StringBuilder dashboardBuilder, Size size, string title)
|
||||||
|
{
|
||||||
|
var halfWidth = (size.Width - title.Width() - (int)Indentation.BorderWidth * 2 -
|
||||||
|
(int)Indentation.Default * 2) / 2;
|
||||||
|
dashboardBuilder.Append(Symbols.Angles.LeftTop);
|
||||||
|
dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(halfWidth));
|
||||||
|
dashboardBuilder.AppendFormat("{0}{1}{0}", Symbols.Space.Repeat(Convert.ToInt32(Indentation.Default)), title);
|
||||||
|
dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(halfWidth));
|
||||||
|
dashboardBuilder.Append(Symbols.Angles.RightTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RenderMiddleLine(StringBuilder dashboardBuilder, Size size)
|
||||||
|
{
|
||||||
|
var dashboardHeight = size.Height - (int)Indentation.BorderWidth * 2;
|
||||||
|
|
||||||
|
while (dashboardHeight > 0)
|
||||||
|
{
|
||||||
|
var bodyWidth = size.Width - (int)Indentation.BorderWidth * 2;
|
||||||
|
dashboardBuilder.Append(Symbols.Lines.Vertical);
|
||||||
|
dashboardBuilder.Append(Symbols.Space.Repeat(bodyWidth));
|
||||||
|
dashboardBuilder.Append(Symbols.Lines.Vertical);
|
||||||
|
|
||||||
|
dashboardHeight--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RenderBottomLine(StringBuilder dashboardBuilder, Size size)
|
||||||
|
{
|
||||||
|
var width = size.Width - (int)Indentation.BorderWidth * 2;
|
||||||
|
dashboardBuilder.Append(Symbols.Angles.LeftBottom);
|
||||||
|
dashboardBuilder.Append(Symbols.Lines.Horizontal.Repeat(width));
|
||||||
|
dashboardBuilder.Append(Symbols.Angles.RightBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Content Render()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
37
src/TUI/Components/Controls/HeaderContainer.cs
Normal file
37
src/TUI/Components/Controls/HeaderContainer.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using TUI.Components.Controls.Statics;
|
||||||
|
using TUI.Components.Controls.Statics.Hints;
|
||||||
|
using TUI.Engine.Nodes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Containers;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls;
|
||||||
|
|
||||||
|
public class HeaderContainer : IContainer
|
||||||
|
{
|
||||||
|
public Orientation Orientation => Orientation.Horizontal;
|
||||||
|
|
||||||
|
public Nodes Nodes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var versionHints = new VersionHints()
|
||||||
|
.Set(Indentation.Default);
|
||||||
|
|
||||||
|
var tagsHints = new TagHints()
|
||||||
|
.Set(Indentation.Default);
|
||||||
|
|
||||||
|
var appTypeHints = new AppTypeHints()
|
||||||
|
.Set(Indentation.Default);
|
||||||
|
|
||||||
|
var hotkeysHints = new HotkeysHint()
|
||||||
|
.Set(Indentation.Default);
|
||||||
|
|
||||||
|
var logo = new Logo()
|
||||||
|
.Set(Horizontal.Right)
|
||||||
|
.Set(left: Indentation.Default, bottom: Indentation.Default, right: Indentation.Default);
|
||||||
|
|
||||||
|
return new Nodes { versionHints, tagsHints, appTypeHints, hotkeysHints, logo };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs
Normal file
28
src/TUI/Components/Controls/Statics/Hints/AppTypeHints.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
using TUI.UserInterface;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls.Statics.Hints;
|
||||||
|
|
||||||
|
public class AppTypeHints : ComponentStaticBase
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> _hints = new()
|
||||||
|
{
|
||||||
|
{ Icons.NpmPackage, "package" },
|
||||||
|
{ Icons.DockerImage, "image" },
|
||||||
|
{ Icons.Site, "site" },
|
||||||
|
{ Icons.Api, "api" }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var hint in _hints)
|
||||||
|
{
|
||||||
|
builder.Append(hint.Key);
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.AppendLine(hint.Value.Hint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs
Normal file
27
src/TUI/Components/Controls/Statics/Hints/HotkeysHint.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls.Statics.Hints;
|
||||||
|
|
||||||
|
public class HotkeysHint : ComponentStaticBase
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> _hints = new()
|
||||||
|
{
|
||||||
|
{ "", "select prev" },
|
||||||
|
{ "", "select next" },
|
||||||
|
{ "", "toggle head" },
|
||||||
|
{ "", "quit" }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var hint in _hints)
|
||||||
|
{
|
||||||
|
builder.Append(hint.Key.Hint());
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.AppendLine(hint.Value.Hint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
src/TUI/Components/Controls/Statics/Hints/TagHints.cs
Normal file
28
src/TUI/Components/Controls/Statics/Hints/TagHints.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
using TUI.UserInterface;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls.Statics.Hints;
|
||||||
|
|
||||||
|
public class TagHints : ComponentStaticBase
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> _hints = new()
|
||||||
|
{
|
||||||
|
{ Icons.Auth, "Auth" },
|
||||||
|
{ Icons.NetworkPublic, "WWW" },
|
||||||
|
{ Icons.SEO, "SEO" },
|
||||||
|
{ Icons.GitLab, "VCS" }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var hint in _hints)
|
||||||
|
{
|
||||||
|
builder.Append(hint.Key);
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.AppendLine(hint.Value.Hint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
src/TUI/Components/Controls/Statics/Hints/VersionHints.cs
Normal file
27
src/TUI/Components/Controls/Statics/Hints/VersionHints.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls.Statics.Hints;
|
||||||
|
|
||||||
|
public class VersionHints : ComponentStaticBase
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> _hints = new()
|
||||||
|
{
|
||||||
|
{ "", "too new".Info() },
|
||||||
|
{ "", "so good".Hint() },
|
||||||
|
{ "", "be nice".Main() },
|
||||||
|
{ "", "too old".Warning() }
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var hint in _hints)
|
||||||
|
{
|
||||||
|
builder.Append(hint.Key.Hint());
|
||||||
|
builder.Append(Symbols.Space);
|
||||||
|
builder.AppendLine(hint.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/TUI/Components/Controls/Statics/Logo.cs
Normal file
20
src/TUI/Components/Controls/Statics/Logo.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls.Statics;
|
||||||
|
|
||||||
|
public class Logo : ComponentStaticBase
|
||||||
|
{
|
||||||
|
protected override void RenderWithCache(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($" {"╭━━━━┳╮".Main()}{"╱╱".Hint()}{"╭━━━╮".Main()}").Append(Symbols.LineBreak);
|
||||||
|
builder.Append($" {"┃╭╮╭╮┃┃".Main()}{"╱╱".Hint()}{"╰╮╭╮┃".Main()}").Append(Symbols.LineBreak);
|
||||||
|
builder.Append($" {"╰╯┃┃╰┫┃".Main()}{"╱╱╱".Hint()}{"┃┃┃┃".Main()}").Append(Symbols.LineBreak);
|
||||||
|
builder.Append($" {"╱╱".Hint()}{"┃┃".Main()}{"╱".Hint()}{"┃┃".Main()}{"╱".Hint()}{"╭╮┃┃┃┃".Main()}")
|
||||||
|
.Append(Symbols.LineBreak);
|
||||||
|
builder.Append($" {"╱╱╱".Hint()}{"┃┃".Main()}{"╱".Hint()}{"┃╰━╯┣╯╰╯┃".Main()}").Append(Symbols.LineBreak);
|
||||||
|
builder.Append($"{"╱╱╱╱".Hint()}{"╰╯".Main()}{"╱".Hint()}{"╰━━━┻━━━╯".Main()}").Append(Symbols.LineBreak);
|
||||||
|
}
|
||||||
|
}
|
66
src/TUI/Components/Controls/Tag.cs
Normal file
66
src/TUI/Components/Controls/Tag.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System.Text;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Rendering;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
using TUI.UserInterface;
|
||||||
|
|
||||||
|
namespace TUI.Components.Controls;
|
||||||
|
|
||||||
|
public class Tag : ComponentBase
|
||||||
|
{
|
||||||
|
private IEnumerable<string> _tags;
|
||||||
|
private string _gitType;
|
||||||
|
|
||||||
|
public Tag(IRenderingEngine renderingEngine)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(IEnumerable<string> tags, string gitType)
|
||||||
|
{
|
||||||
|
_tags = tags;
|
||||||
|
_gitType = gitType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Horizontal horizontal, Size size)
|
||||||
|
{
|
||||||
|
var tagBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
tagBuilder.Append(GetGitTypeImage(_gitType));
|
||||||
|
tagBuilder.Append(Symbols.Space);
|
||||||
|
tagBuilder.Append(_tags.Have("public") ? Icons.NetworkPublic : Icons.NetworkPrivate);
|
||||||
|
tagBuilder.Append(Symbols.Space);
|
||||||
|
tagBuilder.Append(_tags.Have("seo") ? Icons.SEO : Icons.SEO.Disable());
|
||||||
|
tagBuilder.Append(Symbols.Space);
|
||||||
|
tagBuilder.Append(_tags.Have("auth") ? Icons.Auth : Icons.Auth.Disable());
|
||||||
|
tagBuilder.Append(Symbols.Space);
|
||||||
|
tagBuilder.Append(GetApplicationType());
|
||||||
|
tagBuilder.Append(Symbols.Space);
|
||||||
|
|
||||||
|
// base.Render(tagBuilder, position, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetApplicationType()
|
||||||
|
{
|
||||||
|
foreach (var application in Icons.Applications)
|
||||||
|
if (_tags.Have(application.Value))
|
||||||
|
return application.Key;
|
||||||
|
|
||||||
|
return Icons.Undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char GetGitTypeImage(string gitType) =>
|
||||||
|
gitType switch
|
||||||
|
{
|
||||||
|
"gitlab" => Symbols.GitLab,
|
||||||
|
"github" => Symbols.GitHub,
|
||||||
|
_ => Symbols.Git
|
||||||
|
};
|
||||||
|
|
||||||
|
public override Content Render()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
36
src/TUI/Components/Layouts/DashboardLayout.cs
Normal file
36
src/TUI/Components/Layouts/DashboardLayout.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using TUI.Engine.Nodes;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Nodes.Containers;
|
||||||
|
|
||||||
|
namespace TUI.Components.Layouts;
|
||||||
|
|
||||||
|
public class DashboardLayout : IContainer
|
||||||
|
{
|
||||||
|
public Orientation Orientation { get; } = Orientation.Vertical;
|
||||||
|
|
||||||
|
private INode _header;
|
||||||
|
private INode _footer;
|
||||||
|
|
||||||
|
public Nodes Nodes =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
_header, _footer
|
||||||
|
};
|
||||||
|
|
||||||
|
public DashboardLayout AddHeader(IContainer header)
|
||||||
|
{
|
||||||
|
_header = header;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DashboardLayout AddFooter(IComponent footer)
|
||||||
|
{
|
||||||
|
_footer = footer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Render()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
160
src/TUI/Components/Views/DependenciesView.cs
Normal file
160
src/TUI/Components/Views/DependenciesView.cs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
using TUI.Components.Controls;
|
||||||
|
using TUI.Domain;
|
||||||
|
using TUI.Engine;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
namespace TUI.Components.Views;
|
||||||
|
|
||||||
|
public class DependenciesView : ComponentBase, IComponent
|
||||||
|
{
|
||||||
|
private const string ViewName = "Dependencies";
|
||||||
|
|
||||||
|
private DevelopmentStack _developmentStack;
|
||||||
|
|
||||||
|
public void Bind(DevelopmentStack developmentStack)
|
||||||
|
{
|
||||||
|
_developmentStack = developmentStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Horizontal horizontal, Size size)
|
||||||
|
{
|
||||||
|
var dashboardTitle = _developmentStack.Icon + Symbols.Space + ViewName;
|
||||||
|
var dashboard = new Dashboard(dashboardTitle);
|
||||||
|
|
||||||
|
Add(dashboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private const int TitleWidth = 25;
|
||||||
|
// private const int ColumnWidth = 10;
|
||||||
|
|
||||||
|
// private readonly DashboardControl _dashboard = new();
|
||||||
|
|
||||||
|
// public bool IsFocused
|
||||||
|
// {
|
||||||
|
// get => _dashboard.IsFocused;
|
||||||
|
// set => _dashboard.IsFocused = value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public void Render(ProjectDto projectDto, ControlPosition position)
|
||||||
|
// {
|
||||||
|
// _dashboard.Render(projectDto.Icon + " Dependencies", position);
|
||||||
|
// var header = projectDto.Dependencies.Select(GetConventionVersion).ToArray();
|
||||||
|
// var rows = projectDto.Sources.Select(GetTitle).ToArray();
|
||||||
|
//
|
||||||
|
// var tablePosition = new ControlPosition(
|
||||||
|
// position.Left + Theme.BorderWidth,
|
||||||
|
// position.Top + Theme.BorderWidth);
|
||||||
|
//
|
||||||
|
// var tableProps = new TableProps(header, rows, TitleWidth, ColumnWidth);
|
||||||
|
// _table.Render(tableProps, tablePosition);
|
||||||
|
//
|
||||||
|
// for (var rowId = 0; rowId < rows.Length; rowId++)
|
||||||
|
// {
|
||||||
|
// var actualDependencies = GetDependencies(projectDto.Sources[rowId], projectDto.Dependencies);
|
||||||
|
// _table.RenderRow(rowId + 1, rows[rowId] + actualDependencies);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private static string GetDependencies(SourceDto sourceDto, IEnumerable<DependencyDto> conventionDependencies)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var package = DownloadPackage(sourceDto);
|
||||||
|
//
|
||||||
|
// return string.Join("",
|
||||||
|
// conventionDependencies
|
||||||
|
// .Select(dependency => GetVersion(dependency, package))
|
||||||
|
// .Select(RenderCurrentVersion));
|
||||||
|
// }
|
||||||
|
// catch (HttpRequestException exception)
|
||||||
|
// {
|
||||||
|
// switch (exception.StatusCode)
|
||||||
|
// {
|
||||||
|
// case HttpStatusCode.BadRequest:
|
||||||
|
// return " Request have errors.".Pastel(Palette.ErrorColor);
|
||||||
|
// case HttpStatusCode.Forbidden:
|
||||||
|
// return " Not enough rights.".Pastel(Palette.ErrorColor);
|
||||||
|
// case HttpStatusCode.NotFound:
|
||||||
|
// return " Repository or branch master not found.".Pastel(Palette.ErrorColor);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// throw;
|
||||||
|
// }
|
||||||
|
// catch (Exception exception)
|
||||||
|
// {
|
||||||
|
// Debugger.Break();
|
||||||
|
// return " We tried to send a request but couldn't. Check your configuration.".Pastel(Palette.ErrorColor);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static string GetVersion(DependencyDto dependency, Package package)
|
||||||
|
// {
|
||||||
|
// var currentVersion = package.ParseVersion(dependency.Name);
|
||||||
|
//
|
||||||
|
// if (currentVersion == null) return Icons.NotFound;
|
||||||
|
//
|
||||||
|
// var conventionVersion = dependency.Version?.ToVersion();
|
||||||
|
// return PaintingVersion(currentVersion, conventionVersion);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static string PaintingVersion(Version current, Version? convention)
|
||||||
|
// {
|
||||||
|
// var textVersion = current.ToString();
|
||||||
|
//
|
||||||
|
// if (current > convention) return textVersion.Info();
|
||||||
|
//
|
||||||
|
// if (current < convention)
|
||||||
|
// return current.Major == convention.Major ? textVersion.Primary() : textVersion.Warning();
|
||||||
|
//
|
||||||
|
// return textVersion.Hint();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static string GetConventionVersion(DependencyDto dependencyDto)
|
||||||
|
// {
|
||||||
|
// return dependencyDto.Icon.Pastel(dependencyDto.Color) + dependencyDto.Version.Primary();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static string RenderCurrentVersion(string version)
|
||||||
|
// {
|
||||||
|
// var versionWidth = version.Width();
|
||||||
|
// if (versionWidth == 0) return ' '.Repeat(ColumnWidth - 1) + Icons.NotFound.Hint();
|
||||||
|
//
|
||||||
|
// return ' '.Repeat(ColumnWidth - versionWidth) + version;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static string GetTitle(SourceDto sourceDto)
|
||||||
|
// {
|
||||||
|
// var title = "";
|
||||||
|
//
|
||||||
|
// title += RenderPadding();
|
||||||
|
// title += RenderTags(sourceDto);
|
||||||
|
// if (title.Width() + sourceDto.Name.Length + Theme.Padding <= TitleWidth)
|
||||||
|
// {
|
||||||
|
// title += sourceDto.Name;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// var maxNameWidth = TitleWidth - title.Width() - Theme.Padding;
|
||||||
|
// title += $"{sourceDto.Name[..(maxNameWidth - 1)]}{"#".Hint()}";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// title += RenderPadding();
|
||||||
|
// return $"{title}{' '.Repeat(TitleWidth - title.Width())}";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void Next()
|
||||||
|
// {
|
||||||
|
// _table.Next();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void Previous()
|
||||||
|
// {
|
||||||
|
// _table.Previous();
|
||||||
|
// }
|
||||||
|
public override Content Render()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
using TUI.UserInterface;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public class Copyright : IControl<string>
|
|
||||||
{
|
|
||||||
public void Render(string author, Position position, int? height = 0)
|
|
||||||
{
|
|
||||||
const string icon = "© ";
|
|
||||||
Console.SetCursorPosition(position.Left - icon.Width(), position.Top);
|
|
||||||
|
|
||||||
var copyright = $"{icon}{author}".Hint();
|
|
||||||
Console.Write(copyright);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using TUI.UserInterface;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public class Dashboard : IControl<string>
|
|
||||||
{
|
|
||||||
public bool IsFocused { get; set; }
|
|
||||||
|
|
||||||
public void Render(string title, Position position, int? height = 0)
|
|
||||||
{
|
|
||||||
Console.SetCursorPosition(position.Left, position.Top);
|
|
||||||
|
|
||||||
RenderTopLine(title, IsFocused);
|
|
||||||
|
|
||||||
var marginTop = position.Top;
|
|
||||||
|
|
||||||
var dashboardHeight = height == 0 ? Console.WindowHeight - marginTop : height + Theme.Padding * 2;
|
|
||||||
|
|
||||||
for (var top = marginTop;
|
|
||||||
top < dashboardHeight + marginTop - Theme.BorderWidth * 2 - Theme.Padding * 2;
|
|
||||||
top++)
|
|
||||||
RenderMiddleLine(IsFocused);
|
|
||||||
|
|
||||||
RenderBottomLine(IsFocused);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RenderMiddleLine(bool isFocused)
|
|
||||||
{
|
|
||||||
Console.Write("│".Primary(isFocused));
|
|
||||||
Console.Write(new string(' ', Console.WindowWidth - Theme.BorderWidth * 2));
|
|
||||||
Console.WriteLine("│".Primary(isFocused));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RenderBottomLine(bool isFocused)
|
|
||||||
{
|
|
||||||
var lineWidth = Console.WindowWidth - Theme.BorderWidth * 2;
|
|
||||||
Console.Write("└".Primary(isFocused));
|
|
||||||
Console.Write('─'.Repeat(lineWidth).Primary(isFocused));
|
|
||||||
Console.WriteLine("┘".Primary(isFocused));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RenderTopLine(string title, bool isFocused)
|
|
||||||
{
|
|
||||||
var lineWidth =
|
|
||||||
(Console.WindowWidth - title.Width() - Theme.BorderWidth * 2 - Theme.Padding * 2) /
|
|
||||||
2;
|
|
||||||
|
|
||||||
var topLine = new StringBuilder();
|
|
||||||
topLine.Append("┌");
|
|
||||||
topLine.Append('─'.Repeat(lineWidth));
|
|
||||||
topLine.AppendFormat("{0}{1}{0}", ' '.Repeat(Theme.Padding), title);
|
|
||||||
if (title.Width() % 2 == 1) topLine.Append('─');
|
|
||||||
|
|
||||||
topLine.Append('─'.Repeat(lineWidth));
|
|
||||||
topLine.Append("┐");
|
|
||||||
Console.WriteLine(topLine.ToString().Primary(isFocused));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
using TUI.Dashboards;
|
|
||||||
using TUI.Domain;
|
|
||||||
using TUI.UserInterface;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public class Display
|
|
||||||
{
|
|
||||||
public readonly CommandLine CommandLine;
|
|
||||||
|
|
||||||
public readonly Copyright Copyright;
|
|
||||||
|
|
||||||
public readonly DependencyDashboard DependencyDashboard;
|
|
||||||
public readonly Header Header;
|
|
||||||
private bool _commandLineInDisplay;
|
|
||||||
|
|
||||||
private Project _currentProject;
|
|
||||||
private bool _headerInDisplay = true;
|
|
||||||
|
|
||||||
public Display()
|
|
||||||
{
|
|
||||||
Header = new Header();
|
|
||||||
Copyright = new Copyright();
|
|
||||||
CommandLine = new CommandLine();
|
|
||||||
DependencyDashboard = new DependencyDashboard();
|
|
||||||
Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string FocusedElement { get; set; } = "";
|
|
||||||
|
|
||||||
public void OpenDeps(Project project)
|
|
||||||
{
|
|
||||||
_currentProject = project;
|
|
||||||
var dashboardPosition = new Position(0, Header.Height);
|
|
||||||
DependencyDashboard.IsFocused = true;
|
|
||||||
CommandLine.IsFocused = false;
|
|
||||||
DependencyDashboard.Render(_currentProject, dashboardPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResizeDependencies()
|
|
||||||
{
|
|
||||||
var topPosition = 0;
|
|
||||||
topPosition += _commandLineInDisplay ? CommandLine.Height : 0;
|
|
||||||
topPosition += _headerInDisplay ? Header.Height : 0;
|
|
||||||
var dashboardPosition = new Position(0, topPosition);
|
|
||||||
DependencyDashboard.Render(_currentProject, dashboardPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render()
|
|
||||||
{
|
|
||||||
var headerPosition = new Position(0, 0);
|
|
||||||
Header.Render(headerPosition);
|
|
||||||
|
|
||||||
const string copyrightText = "Kolosov Aleksandr";
|
|
||||||
var copyrightPosition = new Position(
|
|
||||||
Console.WindowWidth - copyrightText.Width(),
|
|
||||||
Console.WindowHeight);
|
|
||||||
Copyright.Render(copyrightText, copyrightPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleHeader()
|
|
||||||
{
|
|
||||||
_headerInDisplay = !_headerInDisplay;
|
|
||||||
if (_headerInDisplay)
|
|
||||||
{
|
|
||||||
var headerPosition = new Position(0, 0);
|
|
||||||
Header.Render(headerPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResizeDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Next()
|
|
||||||
{
|
|
||||||
DependencyDashboard.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Previous()
|
|
||||||
{
|
|
||||||
DependencyDashboard.Previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenCommandLine()
|
|
||||||
{
|
|
||||||
var commandLinePosition = new Position(0, _headerInDisplay ? Header.Height : 0);
|
|
||||||
CommandLine.IsFocused = true;
|
|
||||||
DependencyDashboard.IsFocused = false;
|
|
||||||
FocusedElement = nameof(CommandLine);
|
|
||||||
CommandLine.Render(commandLinePosition);
|
|
||||||
_commandLineInDisplay = true;
|
|
||||||
ResizeDependencies();
|
|
||||||
Console.SetCursorPosition(commandLinePosition.Left + Theme.Padding + Theme.BorderWidth + 2,
|
|
||||||
commandLinePosition.Top + Theme.BorderWidth);
|
|
||||||
Console.CursorVisible = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public interface IControl
|
|
||||||
{
|
|
||||||
void Render(Position position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IControl<in TProps>
|
|
||||||
{
|
|
||||||
// bool IsFocused { get; }
|
|
||||||
|
|
||||||
void Render(TProps props, Position position, int? height);
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public record Position(int Left, int Top);
|
|
@ -1,59 +0,0 @@
|
|||||||
using Pastel;
|
|
||||||
using TUI.UserInterface;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Controls;
|
|
||||||
|
|
||||||
public record TableProps(IEnumerable<string> HeaderCells,
|
|
||||||
IEnumerable<string> Rows,
|
|
||||||
int TitleWidth,
|
|
||||||
int ColumnWidth);
|
|
||||||
|
|
||||||
public class Table : IControl<TableProps>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, string> _rows = new();
|
|
||||||
private Position _position;
|
|
||||||
private int _selectedRowId;
|
|
||||||
|
|
||||||
public void Render(TableProps props, Position position, int? height = 0)
|
|
||||||
{
|
|
||||||
_position = position;
|
|
||||||
Console.SetCursorPosition(_position.Left, _position.Top);
|
|
||||||
|
|
||||||
Console.Write(' '.Repeat(props.TitleWidth));
|
|
||||||
foreach (var headerCell in props.HeaderCells)
|
|
||||||
Console.Write(' '.Repeat(props.ColumnWidth - headerCell.Width()) + headerCell);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RenderRow(int rowId, string rowText, string? bgColor = default)
|
|
||||||
{
|
|
||||||
var padRight = ' '.Repeat(Console.WindowWidth - rowText.Width() - Theme.BorderWidth * 2);
|
|
||||||
_rows[rowId] = rowText + padRight;
|
|
||||||
|
|
||||||
Console.SetCursorPosition(_position.Left, _position.Top + rowId);
|
|
||||||
Console.Write(string.IsNullOrEmpty(bgColor) ? rowText : rowText.PastelBg(bgColor));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Next()
|
|
||||||
{
|
|
||||||
if (_selectedRowId >= _rows.Count) return;
|
|
||||||
|
|
||||||
RemoveHoverFromCurrentRow();
|
|
||||||
RenderRow(++_selectedRowId, _rows[_selectedRowId], Palette.HoverColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveHoverFromCurrentRow()
|
|
||||||
{
|
|
||||||
if (_rows.TryGetValue(_selectedRowId, out var row)) RenderRow(_selectedRowId, row);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Previous()
|
|
||||||
{
|
|
||||||
if (_selectedRowId == 0) Next();
|
|
||||||
|
|
||||||
if (_selectedRowId == 1) return;
|
|
||||||
|
|
||||||
RemoveHoverFromCurrentRow();
|
|
||||||
RenderRow(--_selectedRowId, _rows[_selectedRowId], Palette.HoverColor);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,207 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Pastel;
|
|
||||||
using TUI.Controls;
|
|
||||||
using TUI.Domain;
|
|
||||||
using TUI.Settings;
|
|
||||||
using TUI.UserInterface;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Dashboards;
|
|
||||||
|
|
||||||
public class DependencyDashboard : IControl<Project>
|
|
||||||
{
|
|
||||||
private const int TitleWidth = 25;
|
|
||||||
private const int ColumnWidth = 10;
|
|
||||||
|
|
||||||
private readonly static Dictionary<string, Package> Packages = new();
|
|
||||||
private readonly Dashboard _dashboard = new();
|
|
||||||
|
|
||||||
private readonly Table _table = new();
|
|
||||||
|
|
||||||
public bool IsFocused
|
|
||||||
{
|
|
||||||
get => _dashboard.IsFocused;
|
|
||||||
set => _dashboard.IsFocused = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Render(Project project, Position position, int? height = 0)
|
|
||||||
{
|
|
||||||
_dashboard.Render(project.Icon + " Dependencies", position);
|
|
||||||
var header = project.Dependencies.Select(GetConventionVersion).ToArray();
|
|
||||||
var rows = project.Sources.Select(GetTitle).ToArray();
|
|
||||||
|
|
||||||
var tablePosition = new Position(
|
|
||||||
position.Left + Theme.BorderWidth,
|
|
||||||
position.Top + Theme.BorderWidth);
|
|
||||||
|
|
||||||
var tableProps = new TableProps(header, rows, TitleWidth, ColumnWidth);
|
|
||||||
|
|
||||||
_table.Render(tableProps, tablePosition);
|
|
||||||
|
|
||||||
for (var rowId = 0; rowId < rows.Length; rowId++)
|
|
||||||
{
|
|
||||||
var actualDependencies = GetDependencies(project.Sources[rowId], project.Dependencies);
|
|
||||||
_table.RenderRow(rowId + 1, rows[rowId] + actualDependencies);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetDependencies(SourceDto sourceDto, IEnumerable<DependencyDto> conventionDependencies)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var package = DownloadPackage(sourceDto);
|
|
||||||
|
|
||||||
return string.Join("",
|
|
||||||
conventionDependencies
|
|
||||||
.Select(dependency => GetVersion(dependency, package))
|
|
||||||
.Select(RenderCurrentVersion));
|
|
||||||
}
|
|
||||||
catch (HttpRequestException exception)
|
|
||||||
{
|
|
||||||
switch (exception.StatusCode)
|
|
||||||
{
|
|
||||||
case HttpStatusCode.BadRequest:
|
|
||||||
return " Request have errors.".Pastel(Palette.ErrorColor);
|
|
||||||
case HttpStatusCode.Forbidden:
|
|
||||||
return " Not enough rights.".Pastel(Palette.ErrorColor);
|
|
||||||
case HttpStatusCode.NotFound:
|
|
||||||
return " Repository or branch master not found.".Pastel(Palette.ErrorColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
|
||||||
{
|
|
||||||
Debugger.Break();
|
|
||||||
return " We tried to send a request but couldn't. Check your configuration.".Pastel(Palette.ErrorColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static string GetVersion(DependencyDto dependency, Package package)
|
|
||||||
{
|
|
||||||
var currentVersion = package.ParseVersion(dependency.Name);
|
|
||||||
|
|
||||||
if (currentVersion == null) return Icons.NotFound;
|
|
||||||
|
|
||||||
var conventionVersion = dependency.Version?.ToVersion();
|
|
||||||
return PaintingVersion(currentVersion, conventionVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string PaintingVersion(Version current, Version? convention)
|
|
||||||
{
|
|
||||||
var textVersion = current.ToString();
|
|
||||||
|
|
||||||
if (current > convention) return textVersion.Info();
|
|
||||||
|
|
||||||
if (current < convention)
|
|
||||||
return current.Major == convention.Major ? textVersion.Primary() : textVersion.Warning();
|
|
||||||
|
|
||||||
return textVersion.Hint();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Package DownloadPackage(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
var endpoint = sourceDto.Tags.Have("gitlab") ? GetGitlabEndpoint(sourceDto) : sourceDto.Repo;
|
|
||||||
if (Packages.TryGetValue(endpoint, out var downloadPackage)) return downloadPackage;
|
|
||||||
|
|
||||||
using HttpClient client = new();
|
|
||||||
var json = client.GetStringAsync(endpoint).GetAwaiter().GetResult();
|
|
||||||
var package = JsonSerializer.Deserialize<Package>(json);
|
|
||||||
Packages.Add(endpoint, package);
|
|
||||||
return package;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetGitlabEndpoint(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
var token = Environment.GetEnvironmentVariable("TLD_GITLAB_PAT");
|
|
||||||
return $"{sourceDto.Repo}/api/v4/projects/{sourceDto.ProjectId}/repository/files/package.json/raw?" +
|
|
||||||
$"private_token={token}&ref=dev";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetConventionVersion(DependencyDto dependencyDto)
|
|
||||||
{
|
|
||||||
return dependencyDto.Icon.Pastel(dependencyDto.Color) + dependencyDto.Version.Primary();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RenderCurrentVersion(string version)
|
|
||||||
{
|
|
||||||
var versionWidth = version.Width();
|
|
||||||
if (versionWidth == 0) return ' '.Repeat(ColumnWidth - 1) + Icons.NotFound.Hint();
|
|
||||||
|
|
||||||
return ' '.Repeat(ColumnWidth - versionWidth) + version;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetTitle(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
var title = "";
|
|
||||||
|
|
||||||
title += RenderPadding();
|
|
||||||
title += RenderTags(sourceDto);
|
|
||||||
if (title.Width() + sourceDto.Name.Length + Theme.Padding <= TitleWidth)
|
|
||||||
{
|
|
||||||
title += sourceDto.Name;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var maxNameWidth = TitleWidth - title.Width() - Theme.Padding;
|
|
||||||
title += $"{sourceDto.Name[..(maxNameWidth - 1)]}{"#".Hint()}";
|
|
||||||
}
|
|
||||||
|
|
||||||
title += RenderPadding();
|
|
||||||
return $"{title}{' '.Repeat(TitleWidth - title.Width())}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RenderPadding()
|
|
||||||
{
|
|
||||||
return new string(' ', Theme.Padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RenderTags(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
var tags = "";
|
|
||||||
tags += GetGitApplication(sourceDto);
|
|
||||||
tags += " ";
|
|
||||||
tags += sourceDto.Tags.Have("public") ? Icons.NetworkPublic : Icons.NetworkPrivate;
|
|
||||||
tags += " ";
|
|
||||||
tags += sourceDto.Tags.Have("seo") ? Icons.SEO : Icons.SEO.Disable();
|
|
||||||
tags += " ";
|
|
||||||
tags += sourceDto.Tags.Have("auth") ? Icons.Auth : Icons.Auth.Disable();
|
|
||||||
tags += " ";
|
|
||||||
tags += GetApplicationType(sourceDto);
|
|
||||||
tags += " ";
|
|
||||||
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetApplicationType(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
foreach (var application in Icons.Applications)
|
|
||||||
if (sourceDto.Tags.Have(application.Value))
|
|
||||||
return application.Key;
|
|
||||||
|
|
||||||
return Icons.Undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetGitApplication(SourceDto sourceDto)
|
|
||||||
{
|
|
||||||
return sourceDto.Repo switch
|
|
||||||
{
|
|
||||||
{ } url when url.Contains("gitlab") => Icons.GitLab,
|
|
||||||
{ } url when url.Contains("github") => Icons.GitHub,
|
|
||||||
_ => Icons.Git
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Next()
|
|
||||||
{
|
|
||||||
_table.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Previous()
|
|
||||||
{
|
|
||||||
_table.Previous();
|
|
||||||
}
|
|
||||||
}
|
|
3
src/TUI/Domain/DevelopmentStack.cs
Normal file
3
src/TUI/Domain/DevelopmentStack.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace TUI.Domain;
|
||||||
|
|
||||||
|
public record DevelopmentStack(string Name, char Icon);
|
@ -1,21 +1,27 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
using TUI.Settings;
|
using TUI.Settings;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.Domain;
|
namespace TUI.Domain;
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
[YamlSerializable]
|
[YamlSerializable]
|
||||||
public class Project
|
public class ProjectDto
|
||||||
{
|
{
|
||||||
[YamlMember]
|
[YamlMember]
|
||||||
|
[DataMember]
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
|
|
||||||
[YamlMember]
|
[YamlMember]
|
||||||
|
[DataMember]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[YamlMember]
|
[YamlMember]
|
||||||
|
[DataMember]
|
||||||
public DependencyDto[] Dependencies { get; set; }
|
public DependencyDto[] Dependencies { get; set; }
|
||||||
|
|
||||||
[YamlMember]
|
[YamlMember]
|
||||||
|
[DataMember]
|
||||||
public IList<SourceDto> Sources { get; set; }
|
public IList<SourceDto> Sources { get; set; }
|
||||||
}
|
}
|
@ -8,7 +8,7 @@ namespace TUI.Domain;
|
|||||||
public class Settings
|
public class Settings
|
||||||
{
|
{
|
||||||
[YamlMember]
|
[YamlMember]
|
||||||
public Project[] Projects { get; set; }
|
public ProjectDto[] Projects { get; set; }
|
||||||
|
|
||||||
public static Settings Init()
|
public static Settings Init()
|
||||||
{
|
{
|
||||||
|
46
src/TUI/Engine/Helper.cs
Normal file
46
src/TUI/Engine/Helper.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Pastel;
|
||||||
|
using TUI.Engine.Nodes;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
|
||||||
|
namespace TUI.Engine;
|
||||||
|
|
||||||
|
public static class Helper
|
||||||
|
{
|
||||||
|
private static readonly Queue<ConsoleColor> Colors = new();
|
||||||
|
|
||||||
|
static Helper()
|
||||||
|
{
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkYellow);
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkMagenta);
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkGreen);
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkCyan);
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkBlue);
|
||||||
|
Colors.Enqueue(ConsoleColor.DarkRed);
|
||||||
|
Colors.Enqueue(ConsoleColor.Cyan);
|
||||||
|
Colors.Enqueue(ConsoleColor.Yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowBackground(NodePosition position, Size size)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
var color = Colors.Dequeue();
|
||||||
|
var top = position.Top;
|
||||||
|
var height = 0;
|
||||||
|
|
||||||
|
while (height < size.Height)
|
||||||
|
{
|
||||||
|
var left = position.Left;
|
||||||
|
var width = 0;
|
||||||
|
while (width < size.Width)
|
||||||
|
{
|
||||||
|
Console.SetCursorPosition(left, top);
|
||||||
|
Console.Write(Symbols.Space.ToString().PastelBg(color));
|
||||||
|
width++;
|
||||||
|
left++;
|
||||||
|
}
|
||||||
|
|
||||||
|
height++;
|
||||||
|
top++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/TUI/Engine/Nodes/Attributes/Alignments/Alignment.cs
Normal file
3
src/TUI/Engine/Nodes/Attributes/Alignments/Alignment.cs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
|
||||||
|
public record Alignment(Horizontal Horizontal, Vertical Vertical);
|
8
src/TUI/Engine/Nodes/Attributes/Alignments/Horizontal.cs
Normal file
8
src/TUI/Engine/Nodes/Attributes/Alignments/Horizontal.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
|
||||||
|
public enum Horizontal
|
||||||
|
{
|
||||||
|
Left = 0,
|
||||||
|
Center = 1,
|
||||||
|
Right = 2,
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
|
||||||
|
public interface IWithAlignment<out TNode> where TNode : INode
|
||||||
|
{
|
||||||
|
public Alignment Alignment { get; }
|
||||||
|
|
||||||
|
public TNode Set(Horizontal horizontal = Horizontal.Left, Vertical vertical = Vertical.Top);
|
||||||
|
}
|
8
src/TUI/Engine/Nodes/Attributes/Alignments/Vertical.cs
Normal file
8
src/TUI/Engine/Nodes/Attributes/Alignments/Vertical.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
|
||||||
|
public enum Vertical
|
||||||
|
{
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom,
|
||||||
|
}
|
17
src/TUI/Engine/Nodes/Attributes/Paddings/IWithPadding.cs
Normal file
17
src/TUI/Engine/Nodes/Attributes/Paddings/IWithPadding.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Attributes.Paddings;
|
||||||
|
|
||||||
|
public interface IWithPadding<out TNode> where TNode : INode
|
||||||
|
{
|
||||||
|
public Padding? Padding { get; }
|
||||||
|
|
||||||
|
public TNode Set(Level padding);
|
||||||
|
|
||||||
|
public TNode Set(
|
||||||
|
Level? left = Level.None,
|
||||||
|
Level? top = Level.None,
|
||||||
|
Level? right = Level.None,
|
||||||
|
Level? bottom = Level.None
|
||||||
|
);
|
||||||
|
}
|
15
src/TUI/Engine/Nodes/Attributes/Paddings/Padding.cs
Normal file
15
src/TUI/Engine/Nodes/Attributes/Paddings/Padding.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Attributes.Paddings;
|
||||||
|
|
||||||
|
public record Padding(
|
||||||
|
Level? Left = Level.None,
|
||||||
|
Level? Top = Level.None,
|
||||||
|
Level? Right = Level.None,
|
||||||
|
Level? Bottom = Level.None
|
||||||
|
)
|
||||||
|
{
|
||||||
|
public Padding(Level padding) : this(Left: padding, Top: padding, Right: padding, Bottom: padding)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
6
src/TUI/Engine/Nodes/Attributes/Size.cs
Normal file
6
src/TUI/Engine/Nodes/Attributes/Size.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Attributes;
|
||||||
|
|
||||||
|
public record Size(int Width, int Height)
|
||||||
|
{
|
||||||
|
public override string ToString() => $"W[{Width}] H[{Height}]";
|
||||||
|
}
|
45
src/TUI/Engine/Nodes/Components/ComponentBase.cs
Normal file
45
src/TUI/Engine/Nodes/Components/ComponentBase.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Paddings;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
public abstract class ComponentBase : List<IComponent>, IComponent
|
||||||
|
{
|
||||||
|
public abstract Content Render();
|
||||||
|
|
||||||
|
#region Alignments
|
||||||
|
|
||||||
|
public Alignment Alignment { get; private set; } = new(Horizontal.Center, Vertical.Top);
|
||||||
|
|
||||||
|
public IComponent Set(Horizontal horizontal = Horizontal.Left, Vertical vertical = Vertical.Top)
|
||||||
|
{
|
||||||
|
Alignment = new Alignment(horizontal, vertical);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Paddings
|
||||||
|
|
||||||
|
public Padding Padding { get; private set; } = new(Level.None);
|
||||||
|
|
||||||
|
public IComponent Set(Level padding)
|
||||||
|
{
|
||||||
|
Padding = new Padding(padding);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IComponent Set(
|
||||||
|
Level? left = Level.None,
|
||||||
|
Level? top = Level.None,
|
||||||
|
Level? right = Level.None,
|
||||||
|
Level? bottom = Level.None
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Padding = new Padding(left, top, right, bottom);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
24
src/TUI/Engine/Nodes/Components/ComponentStaticBase.cs
Normal file
24
src/TUI/Engine/Nodes/Components/ComponentStaticBase.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
public abstract class ComponentStaticBase : ComponentBase
|
||||||
|
{
|
||||||
|
private Content? _cache;
|
||||||
|
|
||||||
|
protected abstract void RenderWithCache(StringBuilder builder);
|
||||||
|
|
||||||
|
public override Content Render()
|
||||||
|
{
|
||||||
|
if (_cache is not null)
|
||||||
|
{
|
||||||
|
return _cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
RenderWithCache(builder);
|
||||||
|
_cache = new Content(builder.ToString());
|
||||||
|
|
||||||
|
return _cache;
|
||||||
|
}
|
||||||
|
}
|
26
src/TUI/Engine/Nodes/Components/Content.cs
Normal file
26
src/TUI/Engine/Nodes/Components/Content.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
public sealed class Content : IEnumerable<string>
|
||||||
|
{
|
||||||
|
private IEnumerable<string> ContentRows { get; }
|
||||||
|
|
||||||
|
public Content(string content) => ContentRows = content.Split(Symbols.LineBreak);
|
||||||
|
|
||||||
|
public IEnumerator<string> GetEnumerator() => ContentRows.GetEnumerator();
|
||||||
|
|
||||||
|
public IEnumerable<string> Rows(int maxWidth, int maxHeight) =>
|
||||||
|
ContentRows.Where(row => maxWidth >= row.Width()).Take(maxHeight).ToArray();
|
||||||
|
|
||||||
|
public Size GetSize()
|
||||||
|
{
|
||||||
|
var width = ContentRows.Select(row => row.Width()).DefaultIfEmpty(0).Max();
|
||||||
|
var height = ContentRows.Count();
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => string.Join(Symbols.LineBreak, ContentRows);
|
||||||
|
|
||||||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
11
src/TUI/Engine/Nodes/Components/IComponent.cs
Normal file
11
src/TUI/Engine/Nodes/Components/IComponent.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Paddings;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Nodes.Components;
|
||||||
|
|
||||||
|
public interface IComponent : INode,
|
||||||
|
IWithAlignment<IComponent>,
|
||||||
|
IWithPadding<IComponent>
|
||||||
|
{
|
||||||
|
Content Render();
|
||||||
|
}
|
8
src/TUI/Engine/Nodes/Containers/IContainer.cs
Normal file
8
src/TUI/Engine/Nodes/Containers/IContainer.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Containers;
|
||||||
|
|
||||||
|
public interface IContainer : INode
|
||||||
|
{
|
||||||
|
public Orientation Orientation { get; }
|
||||||
|
|
||||||
|
public Nodes Nodes { get; }
|
||||||
|
}
|
7
src/TUI/Engine/Nodes/Containers/Orientation.cs
Normal file
7
src/TUI/Engine/Nodes/Containers/Orientation.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace TUI.Engine.Nodes.Containers;
|
||||||
|
|
||||||
|
public enum Orientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
}
|
5
src/TUI/Engine/Nodes/INode.cs
Normal file
5
src/TUI/Engine/Nodes/INode.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace TUI.Engine.Nodes;
|
||||||
|
|
||||||
|
public interface INode
|
||||||
|
{
|
||||||
|
}
|
6
src/TUI/Engine/Nodes/NodePosition.cs
Normal file
6
src/TUI/Engine/Nodes/NodePosition.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace TUI.Engine.Nodes;
|
||||||
|
|
||||||
|
public record NodePosition(int Left, int Top)
|
||||||
|
{
|
||||||
|
public override string ToString() => $"L[{Left}] T[{Top}]";
|
||||||
|
}
|
5
src/TUI/Engine/Nodes/Nodes.cs
Normal file
5
src/TUI/Engine/Nodes/Nodes.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace TUI.Engine.Nodes;
|
||||||
|
|
||||||
|
public class Nodes : List<INode>
|
||||||
|
{
|
||||||
|
}
|
129
src/TUI/Engine/Rendering/ConsoleRenderingEngine.cs
Normal file
129
src/TUI/Engine/Rendering/ConsoleRenderingEngine.cs
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using TUI.Engine.Nodes;
|
||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Nodes.Containers;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Rendering;
|
||||||
|
|
||||||
|
public class ConsoleRenderingEngine : IRenderingEngine
|
||||||
|
{
|
||||||
|
private readonly IWindow _window;
|
||||||
|
|
||||||
|
public ConsoleRenderingEngine(IWindow window)
|
||||||
|
{
|
||||||
|
_window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(IContainer container, Size? defaultSize = null)
|
||||||
|
{
|
||||||
|
defaultSize ??= new Size(_window.Width, _window.Height);
|
||||||
|
|
||||||
|
var defaultChildrenSize = new Size(
|
||||||
|
Width: container.Orientation == Orientation.Horizontal
|
||||||
|
? defaultSize.Width / container.Nodes.Count
|
||||||
|
: defaultSize.Width,
|
||||||
|
Height: container.Orientation == Orientation.Vertical
|
||||||
|
? defaultSize.Height / container.Nodes.Count
|
||||||
|
: defaultSize.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
var controlNumber = 0;
|
||||||
|
var nodePosition = new NodePosition(Left: 0, Top: 0);
|
||||||
|
|
||||||
|
Debugger.Log(0, "Render", $"{nodePosition} {defaultSize} {container.GetType().Name}\n");
|
||||||
|
Helper.ShowBackground(nodePosition, defaultSize);
|
||||||
|
|
||||||
|
while (controlNumber < container.Nodes.Count)
|
||||||
|
{
|
||||||
|
var node = container.Nodes[controlNumber];
|
||||||
|
|
||||||
|
nodePosition = RenderNode(node, container.Orientation, defaultChildrenSize, nodePosition);
|
||||||
|
controlNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private NodePosition RenderNode(INode node, Orientation orientation, Size defaultSize, NodePosition position)
|
||||||
|
{
|
||||||
|
switch (node)
|
||||||
|
{
|
||||||
|
case IContainer container when orientation == Orientation.Horizontal:
|
||||||
|
Render(container, defaultSize);
|
||||||
|
return position with
|
||||||
|
{
|
||||||
|
Left = position.Left + defaultSize.Width
|
||||||
|
};
|
||||||
|
case IContainer container when orientation == Orientation.Vertical:
|
||||||
|
Render(container, defaultSize);
|
||||||
|
return position with
|
||||||
|
{
|
||||||
|
Top = position.Top + defaultSize.Height
|
||||||
|
};
|
||||||
|
case IComponent component when orientation == Orientation.Horizontal:
|
||||||
|
var componentWidth = RenderComponent(component, position, defaultSize).Width;
|
||||||
|
return position with
|
||||||
|
{
|
||||||
|
Left = position.Left + (defaultSize.Width <= componentWidth ? componentWidth : defaultSize.Width)
|
||||||
|
};
|
||||||
|
case IComponent component when orientation == Orientation.Vertical:
|
||||||
|
var componentHeight = RenderComponent(component, position, defaultSize).Height;
|
||||||
|
return position with
|
||||||
|
{
|
||||||
|
Top = position.Top + (defaultSize.Height <= componentHeight ? componentHeight : defaultSize.Height)
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new InvalidCastException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Size RenderComponent(IComponent component, NodePosition defaultPosition, Size defaultSize)
|
||||||
|
{
|
||||||
|
var content = component.Render();
|
||||||
|
|
||||||
|
var maxWidth = _window.Width - defaultPosition.Left;
|
||||||
|
var maxHeight = _window.Height - defaultPosition.Top;
|
||||||
|
|
||||||
|
var leftPosition = defaultPosition.Left + (int)(component.Padding?.Left ?? 0) +
|
||||||
|
CompensationLeft(component.Alignment.Horizontal, defaultSize, content.GetSize());
|
||||||
|
var topPosition = defaultPosition.Top + (int)(component.Padding?.Top ?? 0) +
|
||||||
|
CompensationTop(component.Alignment.Vertical, defaultSize, content.GetSize());
|
||||||
|
|
||||||
|
|
||||||
|
Debugger.Log(0, "Render", $"{component.GetType().Name} with position [{leftPosition},{topPosition}]\n");
|
||||||
|
|
||||||
|
var rows = content.Rows(maxWidth, maxHeight);
|
||||||
|
|
||||||
|
Helper.ShowBackground(defaultPosition, defaultSize);
|
||||||
|
|
||||||
|
foreach (var row in rows)
|
||||||
|
{
|
||||||
|
_window.SetCursorPosition(leftPosition, topPosition);
|
||||||
|
_window.Write(row);
|
||||||
|
|
||||||
|
topPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CompensationLeft(Horizontal componentHorizontal, Size defaultSize, Size realSize) =>
|
||||||
|
componentHorizontal switch
|
||||||
|
{
|
||||||
|
Horizontal.Left => 0,
|
||||||
|
Horizontal.Center => (defaultSize.Width - realSize.Width) / 2,
|
||||||
|
Horizontal.Right => defaultSize.Width - realSize.Width,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int CompensationTop(Vertical componentVertical, Size defaultSize, Size realSize)
|
||||||
|
=>
|
||||||
|
componentVertical switch
|
||||||
|
{
|
||||||
|
Vertical.Top => 0,
|
||||||
|
Vertical.Center => (defaultSize.Height - realSize.Height) / 2,
|
||||||
|
Vertical.Bottom => defaultSize.Height - realSize.Height,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
}
|
9
src/TUI/Engine/Rendering/ConsoleWindow.cs
Normal file
9
src/TUI/Engine/Rendering/ConsoleWindow.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace TUI.Engine.Rendering;
|
||||||
|
|
||||||
|
public class ConsoleWindow : IWindow
|
||||||
|
{
|
||||||
|
public int Width => Console.WindowWidth;
|
||||||
|
public int Height => Console.WindowHeight;
|
||||||
|
public void SetCursorPosition(int left, int top) => Console.SetCursorPosition(left, top);
|
||||||
|
public void Write(string value) => Console.Write(value);
|
||||||
|
}
|
9
src/TUI/Engine/Rendering/IRenderingEngine.cs
Normal file
9
src/TUI/Engine/Rendering/IRenderingEngine.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using TUI.Engine.Nodes.Attributes;
|
||||||
|
using TUI.Engine.Nodes.Containers;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Rendering;
|
||||||
|
|
||||||
|
public interface IRenderingEngine
|
||||||
|
{
|
||||||
|
void Render(IContainer container, Size? defaultSize);
|
||||||
|
}
|
9
src/TUI/Engine/Rendering/IWindow.cs
Normal file
9
src/TUI/Engine/Rendering/IWindow.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace TUI.Engine.Rendering;
|
||||||
|
|
||||||
|
public interface IWindow
|
||||||
|
{
|
||||||
|
int Width { get; }
|
||||||
|
int Height { get; }
|
||||||
|
void SetCursorPosition(int left, int top);
|
||||||
|
void Write(string value);
|
||||||
|
}
|
25
src/TUI/Engine/Symbols.cs
Normal file
25
src/TUI/Engine/Symbols.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace TUI.Engine;
|
||||||
|
|
||||||
|
public static class Symbols
|
||||||
|
{
|
||||||
|
public const char Space = ' ';
|
||||||
|
public const char Copyright = '©';
|
||||||
|
public const char GitLab = '';
|
||||||
|
public const char GitHub = '';
|
||||||
|
public const char Git = '';
|
||||||
|
public const char LineBreak = '\n';
|
||||||
|
|
||||||
|
public static class Lines
|
||||||
|
{
|
||||||
|
public const char Vertical = '│';
|
||||||
|
public const char Horizontal = '─';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Angles
|
||||||
|
{
|
||||||
|
public const char RightTop = '┐';
|
||||||
|
public const char LeftBottom = '└';
|
||||||
|
public const char LeftTop = '┌';
|
||||||
|
public const char RightBottom = '┘';
|
||||||
|
}
|
||||||
|
}
|
7
src/TUI/Engine/Theme/Indentation.cs
Normal file
7
src/TUI/Engine/Theme/Indentation.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace TUI.Engine.Theme;
|
||||||
|
|
||||||
|
public static class Indentation
|
||||||
|
{
|
||||||
|
public const Level Default = Level.Normal;
|
||||||
|
public const Level BorderWidth = Level.Normal;
|
||||||
|
}
|
7
src/TUI/Engine/Theme/Level.cs
Normal file
7
src/TUI/Engine/Theme/Level.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace TUI.Engine.Theme;
|
||||||
|
|
||||||
|
public enum Level
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Normal = 1
|
||||||
|
}
|
28
src/TUI/Engine/Theme/Palette.cs
Normal file
28
src/TUI/Engine/Theme/Palette.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Pastel;
|
||||||
|
|
||||||
|
namespace TUI.Engine.Theme;
|
||||||
|
|
||||||
|
public static class Palette
|
||||||
|
{
|
||||||
|
private const string HoverColor = "292928";
|
||||||
|
private const string PrimaryColor = "84BA64";
|
||||||
|
private const string HintColor = "71797E";
|
||||||
|
private const string ErrorColor = "CA3433";
|
||||||
|
private const string WarningColor = "EC9706";
|
||||||
|
private const string InfoColor = "25799F";
|
||||||
|
|
||||||
|
public static string Main(this string currentText, bool isFocused = true) =>
|
||||||
|
isFocused
|
||||||
|
? currentText.Pastel(PrimaryColor)
|
||||||
|
: Hint(currentText);
|
||||||
|
|
||||||
|
public static string Hint(this string currentText) => currentText.Pastel(HintColor);
|
||||||
|
|
||||||
|
public static string Disable(this string currentText) => currentText.RemoveColors().Pastel(HintColor);
|
||||||
|
|
||||||
|
public static string Warning(this string currentText) => currentText.Pastel(WarningColor);
|
||||||
|
|
||||||
|
public static string Error(this string currentText) => currentText.Pastel(ErrorColor);
|
||||||
|
|
||||||
|
public static string Info(this string currentText) => currentText.Pastel(InfoColor);
|
||||||
|
}
|
@ -13,7 +13,7 @@ public static class Extensions
|
|||||||
|
|
||||||
public static string Repeat(this char symbol, int repeatCount)
|
public static string Repeat(this char symbol, int repeatCount)
|
||||||
{
|
{
|
||||||
return repeatCount < 0 ? "" : new string(symbol, repeatCount);
|
return repeatCount < 0 ? string.Empty : new string(symbol, repeatCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string RemoveColors(this string text)
|
public static string RemoveColors(this string text)
|
||||||
@ -30,7 +30,7 @@ public static class Extensions
|
|||||||
return stringInfo.LengthInTextElements;
|
return stringInfo.LengthInTextElements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Version? ToVersion(this string textVersion)
|
public static Version ToVersion(this string textVersion)
|
||||||
{
|
{
|
||||||
var version = textVersion.Replace("^", "").Replace("~", "").Split(".");
|
var version = textVersion.Replace("^", "").Replace("~", "").Split(".");
|
||||||
var major = Convert.ToInt32(version[0]);
|
var major = Convert.ToInt32(version[0]);
|
||||||
|
103
src/TUI/Pages/DependenciesPage.cs
Normal file
103
src/TUI/Pages/DependenciesPage.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using TUI.Components.Controls;
|
||||||
|
using TUI.Components.Layouts;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Rendering;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace TUI.Pages;
|
||||||
|
|
||||||
|
public class DependenciesPage
|
||||||
|
{
|
||||||
|
public void Open()
|
||||||
|
{
|
||||||
|
Debugger.Log(0, "Event", "Open page dependencies\n");
|
||||||
|
|
||||||
|
var window = new ConsoleWindow();
|
||||||
|
var renderEngine = new ConsoleRenderingEngine(window);
|
||||||
|
var header = new HeaderContainer();
|
||||||
|
var copyright = new Copyright()
|
||||||
|
.Set(right: Level.Normal)
|
||||||
|
.Set(Horizontal.Right, Vertical.Bottom);
|
||||||
|
|
||||||
|
var layout = new DashboardLayout().AddHeader(header).AddFooter(copyright);
|
||||||
|
// CommandLine = new CommandLine();
|
||||||
|
// DependenciesView = new DependenciesView();
|
||||||
|
renderEngine.Render(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private bool _commandLineInDisplay;
|
||||||
|
|
||||||
|
// private ProjectDto _currentProjectDto;
|
||||||
|
|
||||||
|
// private bool _headerInDisplay = true;
|
||||||
|
|
||||||
|
|
||||||
|
// public string FocusedElement { get; set; } = "";
|
||||||
|
|
||||||
|
// public void OpenDeps(ProjectDto projectDto)
|
||||||
|
// {
|
||||||
|
// _currentProjectDto = projectDto;
|
||||||
|
// var dashboardPosition = new ControlPosition(0, Header.Height);
|
||||||
|
// // DependencyDashboard.IsFocused = true;
|
||||||
|
// // CommandLine.IsFocused = false;
|
||||||
|
// DependenciesView.Render(_currentProjectDto, dashboardPosition);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private void ResizeDependencies()
|
||||||
|
// {
|
||||||
|
// var topPosition = 0;
|
||||||
|
// topPosition += _commandLineInDisplay ? CommandLine.Height : 0;
|
||||||
|
// topPosition += _headerInDisplay ? Header.Height : 0;
|
||||||
|
// var dashboardPosition = new ControlPosition(0, topPosition);
|
||||||
|
// DependenciesView.Render(_currentProjectDto, dashboardPosition);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void Render()
|
||||||
|
// {
|
||||||
|
// var headerPosition = new ControlPosition(0, 0);
|
||||||
|
// Header.Render(headerPosition);
|
||||||
|
//
|
||||||
|
// const string copyrightText = "Kolosov Aleksandr";
|
||||||
|
// var copyrightPosition = new ControlPosition(
|
||||||
|
// Console.WindowWidth - copyrightText.Width(),
|
||||||
|
// Console.WindowHeight);
|
||||||
|
// CopyrightControl.Render(copyrightText, copyrightPosition);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void ToggleHeader()
|
||||||
|
// {
|
||||||
|
// _headerInDisplay = !_headerInDisplay;
|
||||||
|
// if (_headerInDisplay)
|
||||||
|
// {
|
||||||
|
// var headerPosition = new ControlPosition(0, 0);
|
||||||
|
// Header.Render(headerPosition);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ResizeDependencies();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void Next()
|
||||||
|
// {
|
||||||
|
// DependenciesView.Next();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void Previous()
|
||||||
|
// {
|
||||||
|
// DependenciesView.Previous();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public void OpenCommandLine()
|
||||||
|
// {
|
||||||
|
// var commandLinePosition = new ControlPosition(0, _headerInDisplay ? Header.Height : 0);
|
||||||
|
// // CommandLine.IsFocused = true;
|
||||||
|
// // DependencyDashboard.IsFocused = false;
|
||||||
|
// FocusedElement = nameof(CommandLine);
|
||||||
|
// CommandLine.Render(commandLinePosition);
|
||||||
|
// _commandLineInDisplay = true;
|
||||||
|
// ResizeDependencies();
|
||||||
|
// Console.SetCursorPosition(commandLinePosition.Left + Theme.Padding + Theme.BorderWidth + 2,
|
||||||
|
// commandLinePosition.Top + Theme.BorderWidth);
|
||||||
|
// Console.CursorVisible = true;
|
||||||
|
// }
|
||||||
|
}
|
@ -1,60 +1,61 @@
|
|||||||
using TUI.Controls;
|
using TUI.Pages;
|
||||||
using TUI.Domain;
|
|
||||||
|
|
||||||
|
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
Console.CursorVisible = false;
|
Console.CursorVisible = false;
|
||||||
|
|
||||||
var settings = Settings.Init();
|
// var settings = Settings.Init();
|
||||||
|
|
||||||
var display = new Display();
|
var dependenciesPage = new DependenciesPage();
|
||||||
display.OpenDeps(settings.Projects[0]);
|
dependenciesPage.Open();
|
||||||
|
|
||||||
|
// display.OpenDeps(settings.Projects[0]);
|
||||||
|
|
||||||
var key = new ConsoleKeyInfo('1', ConsoleKey.NoName, false, false, false);
|
var key = new ConsoleKeyInfo('1', ConsoleKey.NoName, false, false, false);
|
||||||
var waitCommand = true;
|
var waitCommand = true;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (key.Key == ConsoleKey.Q && !display.CommandLine.IsFocused)
|
// if (key.Key == ConsoleKey.Q && !display.CommandLine.IsFocused)
|
||||||
{
|
// {
|
||||||
waitCommand = false;
|
// waitCommand = false;
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (display.CommandLine.IsFocused)
|
// if (display.CommandLine.IsFocused)
|
||||||
{
|
// {
|
||||||
switch (key.Key)
|
// switch (key.Key)
|
||||||
{
|
// {
|
||||||
case ConsoleKey.Escape:
|
// case ConsoleKey.Escape:
|
||||||
display.CommandLine.IsFocused = false;
|
// display.CommandLine.IsFocused = false;
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
Console.Write(key.KeyChar);
|
// Console.Write(key.KeyChar);
|
||||||
|
//
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
switch (key.KeyChar)
|
// switch (key.KeyChar)
|
||||||
{
|
// {
|
||||||
case ':':
|
// case ':':
|
||||||
display.OpenCommandLine();
|
// display.OpenCommandLine();
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
switch (key.Key)
|
// switch (key.Key)
|
||||||
{
|
// {
|
||||||
case ConsoleKey.DownArrow:
|
// case ConsoleKey.DownArrow:
|
||||||
display.Next();
|
// display.Next();
|
||||||
break;
|
// break;
|
||||||
case ConsoleKey.UpArrow:
|
// case ConsoleKey.UpArrow:
|
||||||
display.Previous();
|
// display.Previous();
|
||||||
break;
|
// break;
|
||||||
case ConsoleKey.E:
|
// case ConsoleKey.E:
|
||||||
display.ToggleHeader();
|
// display.Toggle();
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
key = Console.ReadKey(true);
|
key = Console.ReadKey(true);
|
||||||
} while (waitCommand);
|
} while (waitCommand);
|
||||||
|
29
src/TUI/Store/DependenciesStore.cs
Normal file
29
src/TUI/Store/DependenciesStore.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using TUI.Domain;
|
||||||
|
using TUI.Settings;
|
||||||
|
|
||||||
|
namespace TUI.Store;
|
||||||
|
|
||||||
|
public static class DependenciesStore
|
||||||
|
{
|
||||||
|
private readonly static Dictionary<string, Package> Packages = new();
|
||||||
|
|
||||||
|
private static Package DownloadPackage(SourceDto sourceDto)
|
||||||
|
{
|
||||||
|
var endpoint = sourceDto.Tags.Have("gitlab") ? GetGitlabEndpoint(sourceDto) : sourceDto.Repo;
|
||||||
|
if (Packages.TryGetValue(endpoint, out var downloadPackage)) return downloadPackage;
|
||||||
|
|
||||||
|
using HttpClient client = new();
|
||||||
|
var json = client.GetStringAsync(endpoint).GetAwaiter().GetResult();
|
||||||
|
var package = JsonSerializer.Deserialize<Package>(json);
|
||||||
|
Packages.Add(endpoint, package);
|
||||||
|
return package;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetGitlabEndpoint(SourceDto sourceDto)
|
||||||
|
{
|
||||||
|
var token = Environment.GetEnvironmentVariable("TLD_GITLAB_PAT");
|
||||||
|
return $"{sourceDto.Repo}/api/v4/projects/{sourceDto.ProjectId}/repository/files/package.json/raw?" +
|
||||||
|
$"private_token={token}&ref=dev";
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,19 @@
|
|||||||
using TUI.Controls;
|
// using TUI.Components.Controls;
|
||||||
|
// using TUI.Engine;
|
||||||
|
// using TUI.Engine.Controls;
|
||||||
namespace TUI.UserInterface;
|
//
|
||||||
|
//
|
||||||
public class CommandLine : Dashboard
|
// namespace TUI.UserInterface;
|
||||||
{
|
// //
|
||||||
public const int Height = 3;
|
// // public class CommandLine : DashboardControl
|
||||||
|
// // {
|
||||||
public void Render(Position position)
|
// // public const int Height = 3;
|
||||||
{
|
// //
|
||||||
base.Render("Command", position, Height);
|
// // public void Render(ControlPosition position)
|
||||||
|
// // {
|
||||||
Console.SetCursorPosition(position.Left + Theme.BorderWidth + Theme.Padding, position.Top + Theme.BorderWidth);
|
// // base.Render("Command", position, Height);
|
||||||
Console.Write(">");
|
// //
|
||||||
}
|
// // Console.SetCursorPosition(position.Left + Theme.BorderWidth + Theme.Padding, position.Top + Theme.BorderWidth);
|
||||||
}
|
// // Console.Write(">");
|
||||||
|
// // }
|
||||||
|
// // }
|
@ -1,79 +0,0 @@
|
|||||||
using TUI.Controls;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.UserInterface;
|
|
||||||
|
|
||||||
public class Header : IControl
|
|
||||||
{
|
|
||||||
public const int LogoWidth = 16;
|
|
||||||
public const int Height = 6;
|
|
||||||
public const int MaxHeaderBlocksWidth = 16;
|
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _hints = new()
|
|
||||||
{
|
|
||||||
{ "", "too new".Info() },
|
|
||||||
{ "", "so good" },
|
|
||||||
{ "", "be nice".Primary() },
|
|
||||||
{ "", "too old".Warning() }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _hotKeys = new()
|
|
||||||
{
|
|
||||||
{ "", "select prev" },
|
|
||||||
{ "", "select next" },
|
|
||||||
{ "", "toggle head" },
|
|
||||||
{ "", "quit" }
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _tags = new()
|
|
||||||
{
|
|
||||||
{ Icons.Auth, "Auth" },
|
|
||||||
{ Icons.NetworkPublic, "WWW" },
|
|
||||||
{ Icons.SEO, "SEO" },
|
|
||||||
{ Icons.GitLab, "VCS" }
|
|
||||||
};
|
|
||||||
|
|
||||||
public void Render(Position position)
|
|
||||||
{
|
|
||||||
Console.SetCursorPosition(position.Left, position.Top);
|
|
||||||
|
|
||||||
for (var i = 1; i <= Height; i++) Console.WriteLine(new string(' ', Console.WindowWidth - LogoWidth));
|
|
||||||
|
|
||||||
RenderBlock(0, _hints);
|
|
||||||
RenderBlock(1, _tags);
|
|
||||||
RenderBlock(2, Icons.Applications);
|
|
||||||
RenderBlock(3, _hotKeys);
|
|
||||||
RenderLogo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RenderBlock(int blockNumber, Dictionary<string, string> items)
|
|
||||||
{
|
|
||||||
var leftPadding = Theme.Padding + blockNumber * MaxHeaderBlocksWidth;
|
|
||||||
|
|
||||||
var hotKeyNumber = 0;
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
Console.SetCursorPosition(leftPadding, Theme.Padding + hotKeyNumber++);
|
|
||||||
Console.Write((item.Key + " " + item.Value).Hint());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static void RenderLogo()
|
|
||||||
{
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 0);
|
|
||||||
Console.WriteLine(" ╭━━━━┳╮".Primary() + "╱╱".Hint() + "╭━━━╮ ".Primary());
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 1);
|
|
||||||
Console.WriteLine(" ┃╭╮╭╮┃┃".Primary() + "╱╱".Hint() + "╰╮╭╮┃ ".Primary());
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 2);
|
|
||||||
Console.WriteLine(" ╰╯┃┃╰┫┃".Primary() + "╱╱╱".Hint() + "┃┃┃┃ ".Primary());
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 3);
|
|
||||||
Console.WriteLine(" ╱╱".Hint() + "┃┃".Primary() + "╱".Hint() + "┃┃".Primary() + "╱".Hint() +
|
|
||||||
"╭╮┃┃┃┃ ".Primary());
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 4);
|
|
||||||
Console.WriteLine(" ╱╱╱".Hint() + "┃┃".Primary() + "╱".Hint() + "┃╰━╯┣╯╰╯┃ ".Primary());
|
|
||||||
Console.SetCursorPosition(Console.WindowWidth - LogoWidth - Theme.Padding, 5);
|
|
||||||
Console.WriteLine("╱╱╱╱".Hint() + "╰╯".Primary() + "╱".Hint() + "╰━━━┻━━━╯ ".Primary());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using Pastel;
|
using Pastel;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.UserInterface;
|
namespace TUI.UserInterface;
|
||||||
@ -29,6 +30,6 @@ public static class Icons
|
|||||||
|
|
||||||
private static string GetIcon(string icon, string? activeColor = null)
|
private static string GetIcon(string icon, string? activeColor = null)
|
||||||
{
|
{
|
||||||
return icon.Pastel(activeColor ?? Palette.HintColor);
|
return activeColor != null ? icon.Pastel(activeColor) : icon.Hint();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,46 +0,0 @@
|
|||||||
using Pastel;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TUI.UserInterface;
|
|
||||||
|
|
||||||
public static class Palette
|
|
||||||
{
|
|
||||||
public const string HoverColor = "292928";
|
|
||||||
public const string PrimaryColor = "84BA64";
|
|
||||||
public const string HintColor = "71797E";
|
|
||||||
public const string ErrorColor = "CA3433";
|
|
||||||
public const string WarningColor = "EC9706";
|
|
||||||
public const string InfoColor = "25799F";
|
|
||||||
|
|
||||||
public static string Primary(this string currentText, bool isFocused = true)
|
|
||||||
{
|
|
||||||
return isFocused
|
|
||||||
? currentText.Pastel(PrimaryColor)
|
|
||||||
: Hint(currentText);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Hint(this string currentText)
|
|
||||||
{
|
|
||||||
return currentText.Pastel(HintColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Disable(this string currentText)
|
|
||||||
{
|
|
||||||
return currentText.RemoveColors().Pastel(HintColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Warning(this string currentText)
|
|
||||||
{
|
|
||||||
return currentText.Pastel(WarningColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Error(this string currentText)
|
|
||||||
{
|
|
||||||
return currentText.Pastel(ErrorColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Info(this string currentText)
|
|
||||||
{
|
|
||||||
return currentText.Pastel(InfoColor);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
using TUI.Engine.Theme;
|
||||||
using TUI.Settings;
|
using TUI.Settings;
|
||||||
|
|
||||||
|
|
||||||
@ -18,9 +19,9 @@ public static class Panel
|
|||||||
{
|
{
|
||||||
for (var index = 0; index < sources.Length; index++)
|
for (var index = 0; index < sources.Length; index++)
|
||||||
{
|
{
|
||||||
Console.SetCursorPosition(Theme.Padding,
|
Console.SetCursorPosition(Convert.ToInt32(Indentation.Default),
|
||||||
6 + index + _marginTop + BorderWidth +
|
6 + index + _marginTop + BorderWidth +
|
||||||
Theme.Padding);
|
Convert.ToInt32(Indentation.Default));
|
||||||
|
|
||||||
if (selectedRowNumber == index + 1)
|
if (selectedRowNumber == index + 1)
|
||||||
{
|
{
|
||||||
@ -32,7 +33,7 @@ public static class Panel
|
|||||||
|
|
||||||
for (var index = 0; index < sources.Length; index++)
|
for (var index = 0; index < sources.Length; index++)
|
||||||
Console.SetCursorPosition(TitleWidth,
|
Console.SetCursorPosition(TitleWidth,
|
||||||
6 + index + _marginTop + BorderWidth + Theme.Padding);
|
6 + index + _marginTop + BorderWidth + Convert.ToInt32(Indentation.Default));
|
||||||
// var source = sources[index];
|
// var source = sources[index];
|
||||||
// var package = DownloadPackage(source);
|
// var package = DownloadPackage(source);
|
||||||
// var resultText = package.Dependencies.React;
|
// var resultText = package.Dependencies.React;
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
namespace TUI.UserInterface;
|
|
||||||
|
|
||||||
public static class Theme
|
|
||||||
{
|
|
||||||
public static int Padding = 1;
|
|
||||||
public static int BorderWidth = 1;
|
|
||||||
}
|
|
63
tests/WIdgets/TUI.Tests/ComponentBaseTests.cs
Normal file
63
tests/WIdgets/TUI.Tests/ComponentBaseTests.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using TUI.Components.Controls.Statics;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Theme;
|
||||||
|
|
||||||
|
namespace Widgets.Tests;
|
||||||
|
|
||||||
|
public class ComponentBaseTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void WhenUseChainingSaveAllChange()
|
||||||
|
{
|
||||||
|
var component = new Logo()
|
||||||
|
.Set(Level.Normal)
|
||||||
|
.Set(vertical: Vertical.Center, horizontal: Horizontal.Center);
|
||||||
|
|
||||||
|
component.Padding.Top.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Left.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Bottom.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Right.Should().Be(Level.Normal);
|
||||||
|
component.Alignment.Horizontal.Should().Be(Horizontal.Center);
|
||||||
|
component.Alignment.Vertical.Should().Be(Vertical.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WhenSetPaddingsSaveAllChange()
|
||||||
|
{
|
||||||
|
var component = new Logo();
|
||||||
|
|
||||||
|
component.Set(Level.Normal);
|
||||||
|
|
||||||
|
component.Padding.Top.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Left.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Bottom.Should().Be(Level.Normal);
|
||||||
|
component.Padding.Right.Should().Be(Level.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Vertical.Bottom)]
|
||||||
|
[InlineData(Vertical.Center)]
|
||||||
|
[InlineData(Vertical.Top)]
|
||||||
|
public void WhenSetVerticalAlignSaveAllChange(Vertical alignment)
|
||||||
|
{
|
||||||
|
var component = new Logo();
|
||||||
|
|
||||||
|
component.Set(vertical: alignment);
|
||||||
|
|
||||||
|
component.Alignment.Vertical.Should().Be(alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Horizontal.Left)]
|
||||||
|
[InlineData(Horizontal.Center)]
|
||||||
|
[InlineData(Horizontal.Right)]
|
||||||
|
public void WhenSetHorizontalAlignSaveAllChange(Horizontal alignment)
|
||||||
|
{
|
||||||
|
var component = new Logo();
|
||||||
|
|
||||||
|
component.Set(horizontal: alignment);
|
||||||
|
|
||||||
|
component.Alignment.Horizontal.Should().Be(alignment);
|
||||||
|
}
|
||||||
|
}
|
184
tests/WIdgets/TUI.Tests/ConsoleRenderingEngineTests.cs
Normal file
184
tests/WIdgets/TUI.Tests/ConsoleRenderingEngineTests.cs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
using Moq;
|
||||||
|
using TUI.Engine.Nodes;
|
||||||
|
using TUI.Engine.Nodes.Attributes.Alignments;
|
||||||
|
using TUI.Engine.Nodes.Components;
|
||||||
|
using TUI.Engine.Nodes.Containers;
|
||||||
|
using TUI.Engine.Rendering;
|
||||||
|
|
||||||
|
namespace Widgets.Tests;
|
||||||
|
|
||||||
|
public class ConsoleRenderingEngineTests
|
||||||
|
{
|
||||||
|
private readonly IComponent _component;
|
||||||
|
|
||||||
|
public ConsoleRenderingEngineTests()
|
||||||
|
{
|
||||||
|
_component = Mock.Of<IComponent>(c =>
|
||||||
|
c.Render() == new Content("Lorem") &&
|
||||||
|
c.Alignment == new Alignment(Horizontal.Left, Vertical.Top));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderSimple()
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == 9 && w.Height == 1);
|
||||||
|
var nodes = new Nodes { _component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Once());
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Horizontal.Left, "Lorem", 10, 0)]
|
||||||
|
[InlineData(Horizontal.Center, "Lorem", 10, 2)]
|
||||||
|
[InlineData(Horizontal.Center, "Lo", 10, 4)]
|
||||||
|
[InlineData(Horizontal.Center, "Lorem", 9, 2)]
|
||||||
|
[InlineData(Horizontal.Center, "Lorem", 11, 3)]
|
||||||
|
[InlineData(Horizontal.Right, "Lorem", 10, 5)]
|
||||||
|
[InlineData(Horizontal.Right, "Lo", 10, 8)]
|
||||||
|
public void RenderWithHorizontalAlignment(Horizontal alignment, string content, int windowSize,
|
||||||
|
int expectedPosition)
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == windowSize && w.Height == windowSize);
|
||||||
|
var component = Mock.Of<IComponent>(c => c.Render() == new Content(content) &&
|
||||||
|
c.Alignment == new Alignment(alignment, Vertical.Top));
|
||||||
|
var nodes = new Nodes { component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.Write(content), Times.Once());
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(expectedPosition, 0), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Vertical.Top, "v", 5, new[] { 0 })]
|
||||||
|
[InlineData(Vertical.Top, "v\nv", 5, new[] { 0, 1 })]
|
||||||
|
[InlineData(Vertical.Top, "v\nv\nv", 5, new[] { 0, 1, 2 })]
|
||||||
|
[InlineData(Vertical.Center, "v", 1, new[] { 0 })]
|
||||||
|
[InlineData(Vertical.Center, "v", 4, new[] { 1 })]
|
||||||
|
[InlineData(Vertical.Center, "v", 5, new[] { 2 })]
|
||||||
|
[InlineData(Vertical.Center, "v", 6, new[] { 2 })]
|
||||||
|
[InlineData(Vertical.Center, "v\nv", 4, new[] { 1, 2 })]
|
||||||
|
[InlineData(Vertical.Center, "v\nv", 5, new[] { 1, 2 })]
|
||||||
|
[InlineData(Vertical.Center, "v\nv", 6, new[] { 2, 3 })]
|
||||||
|
[InlineData(Vertical.Bottom, "v", 5, new[] { 4 })]
|
||||||
|
[InlineData(Vertical.Bottom, "v\nv", 2, new[] { 0, 1 })]
|
||||||
|
[InlineData(Vertical.Bottom, "v\nv", 3, new[] { 1, 2 })]
|
||||||
|
[InlineData(Vertical.Bottom, "v\nv\nv\nv", 5, new[] { 1, 2, 3, 4 })]
|
||||||
|
public void RenderWithVerticalAlignment(Vertical alignment, string content, int windowSize, int[] expectedPositions)
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == windowSize && w.Height == windowSize);
|
||||||
|
var component = Mock.Of<IComponent>(c => c.Render() == new Content(content) &&
|
||||||
|
c.Alignment == new Alignment(Horizontal.Left, alignment));
|
||||||
|
var nodes = new Nodes { component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
foreach (var expectedCursorPosition in expectedPositions)
|
||||||
|
{
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, expectedCursorPosition), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Horizontal.Left, Vertical.Top, 0, 0)]
|
||||||
|
[InlineData(Horizontal.Left, Vertical.Center, 0, 2)]
|
||||||
|
[InlineData(Horizontal.Left, Vertical.Bottom, 0, 4)]
|
||||||
|
[InlineData(Horizontal.Center, Vertical.Top, 2, 0)]
|
||||||
|
[InlineData(Horizontal.Center, Vertical.Center, 2, 2)]
|
||||||
|
[InlineData(Horizontal.Center, Vertical.Bottom, 2, 4)]
|
||||||
|
[InlineData(Horizontal.Right, Vertical.Top, 4, 0)]
|
||||||
|
[InlineData(Horizontal.Right, Vertical.Center, 4, 2)]
|
||||||
|
[InlineData(Horizontal.Right, Vertical.Bottom, 4, 4)]
|
||||||
|
public void RenderWithAlignment(Horizontal horizontal, Vertical vertical, int expectedLeft, int expectedTop)
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == 6 && w.Height == 5);
|
||||||
|
var component = Mock.Of<IComponent>(c => c.Render() == new Content("VV") &&
|
||||||
|
c.Alignment == new Alignment(horizontal, vertical));
|
||||||
|
var nodes = new Nodes { component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(expectedLeft, expectedTop), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(Orientation.Horizontal, 9, 1)]
|
||||||
|
[InlineData(Orientation.Vertical, 5, 1)]
|
||||||
|
public void RenderWithOverload(Orientation orientation, int rootWidth, int rootHeight)
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == rootWidth && w.Height == rootHeight);
|
||||||
|
var nodes = new Nodes { _component, _component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes && r.Orientation == orientation);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Once());
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderVerticalWithDoubleComponent()
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Height == 2 && w.Width == 10);
|
||||||
|
var nodes = new Nodes { _component, _component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes && r.Orientation == Orientation.Vertical);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Once());
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 1), Times.Once());
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Exactly(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderHorizontalWithDoubleComponent()
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == 10 && w.Height == 1);
|
||||||
|
var nodes = new Nodes { _component, _component };
|
||||||
|
var container = Mock.Of<IContainer>(g => g.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(container);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(5, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Exactly(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderWithMultipleComponent()
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == 24 && w.Height == 1);
|
||||||
|
var nodes = new Nodes { _component, _component, _component, _component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(6, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(12, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(18, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Exactly(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderWithContainerAndComponent()
|
||||||
|
{
|
||||||
|
var window = Mock.Of<IWindow>(w => w.Width == 10 && w.Height == 2);
|
||||||
|
var container = Mock.Of<IContainer>(c => c.Nodes == new Nodes { _component });
|
||||||
|
var nodes = new Nodes { container, _component };
|
||||||
|
var root = Mock.Of<IContainer>(r => r.Nodes == nodes && r.Orientation == Orientation.Vertical);
|
||||||
|
|
||||||
|
new ConsoleRenderingEngine(window).Render(root);
|
||||||
|
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 0), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.SetCursorPosition(0, 1), Times.Exactly(1));
|
||||||
|
Mock.Get(window).Verify(w => w.Write("Lorem"), Times.Exactly(2));
|
||||||
|
}
|
||||||
|
}
|
18
tests/WIdgets/TUI.Tests/Controls/LogoTests.cs
Normal file
18
tests/WIdgets/TUI.Tests/Controls/LogoTests.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using TUI.Components.Controls.Statics;
|
||||||
|
|
||||||
|
namespace Widgets.Tests.Controls;
|
||||||
|
|
||||||
|
public class LogoTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Simple()
|
||||||
|
{
|
||||||
|
var logo = new Logo();
|
||||||
|
|
||||||
|
var render = logo.Render().ToString();
|
||||||
|
|
||||||
|
Assert.Equal(
|
||||||
|
" \u001b[38;2;132;186;100m\u256d\u2501\u2501\u2501\u2501\u2533\u256e\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u256d\u2501\u2501\u2501\u256e\u001b[0m\n \u001b[38;2;132;186;100m\u2503\u256d\u256e\u256d\u256e\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u256e\u256d\u256e\u2503\u001b[0m\n \u001b[38;2;132;186;100m\u2570\u256f\u2503\u2503\u2570\u252b\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u2503\u2503\u001b[0m\n \u001b[38;2;113;121;126m\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u256d\u256e\u2503\u2503\u2503\u2503\u001b[0m\n \u001b[38;2;113;121;126m\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2503\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2503\u2570\u2501\u256f\u2523\u256f\u2570\u256f\u2503\u001b[0m\n\u001b[38;2;113;121;126m\u2571\u2571\u2571\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u256f\u001b[0m\u001b[38;2;113;121;126m\u2571\u001b[0m\u001b[38;2;132;186;100m\u2570\u2501\u2501\u2501\u253b\u2501\u2501\u2501\u256f\u001b[0m\n",
|
||||||
|
render);
|
||||||
|
}
|
||||||
|
}
|
32
tests/WIdgets/TUI.Tests/TUI.Tests.csproj
Normal file
32
tests/WIdgets/TUI.Tests/TUI.Tests.csproj
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
<RootNamespace>Widgets.Tests</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="7.0.0-alpha.3" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0"/>
|
||||||
|
<PackageReference Include="Moq" Version="4.20.70" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\src\TUI\TUI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
1
tests/WIdgets/TUI.Tests/Usings.cs
Normal file
1
tests/WIdgets/TUI.Tests/Usings.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
global using Xunit;
|
Loading…
Reference in New Issue
Block a user