diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f6eeece..69b9b0c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,7 +21,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.301 + dotnet-version: 6.0.x + include-prerelease: true - name: Setup Node.js uses: actions/setup-node@v2 diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 6cadf1e..3fd6568 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -24,7 +24,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.301 + dotnet-version: 6.0.x + include-prerelease: true - name: Setup Node.js uses: actions/setup-node@v2 diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 5bdc37a..2569948 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -29,7 +29,8 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.301 + dotnet-version: 6.0.x + include-prerelease: true - name: Build shell: bash diff --git a/docs/.gitignore b/docs/.gitignore index 56a2f3a..35ae38b 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -7,6 +7,7 @@ [Tt]ools/ ![Tt]ools/packages.config [Oo]utput/ +[Cc]ache/ ![Ii]nput/ nuget.exe *.com diff --git a/docs/Docs.csproj b/docs/Docs.csproj index 84b8fc8..283d4ca 100644 --- a/docs/Docs.csproj +++ b/docs/Docs.csproj @@ -1,10 +1,11 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <OutputType>Exe</OutputType> - <TargetFramework>net5.0</TargetFramework> + <TargetFramework>net6.0</TargetFramework> <RunWorkingDirectory>$(MSBuildProjectDirectory)</RunWorkingDirectory> <DefaultItemExcludes>$(DefaultItemExcludes);output\**;.gitignore</DefaultItemExcludes> + <NoWarn>MVC1000</NoWarn> <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> </PropertyGroup> @@ -31,7 +32,9 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Statiq.Web" Version="1.0.0-beta.27" /> + <PackageReference Include="Microsoft.Playwright" Version="1.13.0-next-1" /> + + <PackageReference Include="Statiq.Web" Version="1.0.0-beta.31" /> <PackageReference Include="MinVer" PrivateAssets="All" Version="2.3.1" /> </ItemGroup> diff --git a/docs/Program.cs b/docs/Program.cs index b1a87c8..a61856c 100644 --- a/docs/Program.cs +++ b/docs/Program.cs @@ -22,7 +22,7 @@ namespace Docs .AddShortcode("Alert", typeof(AlertShortcode)) .AddShortcode("AsciiCast", typeof(AsciiCastShortcode)) .AddPipelines() - .AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("npm", "install") + .AddProcess(ProcessTiming.Initialization, _ => new ProcessLauncher("npm", "install", "--audit", "false", "--fund", "false") { LogErrors = false }) diff --git a/docs/global.json b/docs/global.json new file mode 100644 index 0000000..7281fbf --- /dev/null +++ b/docs/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "2.2.200", + "rollForward": "latestMajor" + } +} \ No newline at end of file diff --git a/docs/input/_layout.cshtml b/docs/input/_layout.cshtml index 78fd1f8..b832749 100644 --- a/docs/input/_layout.cshtml +++ b/docs/input/_layout.cshtml @@ -14,11 +14,21 @@ <link rel="icon" type="image/png" sizes="16x16" href="@Context.GetLink("/assets/favicons/favicon-16x16.png")"> @{ - string title = @Document.ContainsKey(Keys.Title) ? $"Spectre.Console - {Document.GetString(Keys.Title)}" : "Spectre.Console"; - string description = @Document.ContainsKey(Constants.Description) ? Document.GetString(Constants.Description) : "Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications"; + string title = Document.ContainsKey(Keys.Title) ? $"Spectre.Console - {Document.GetString(Keys.Title)}" : "Spectre.Console"; + string description = Document.ContainsKey(Constants.Description) ? Document.GetString(Constants.Description) : "Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications"; + var card = Outputs.FirstOrDefault(i => i.GetString("DocId") == Model.Id.ToString()); + var urlBase = $"https://{Document.GetString(Keys.Host)}/"; } <title>@title</title> <meta name="description" content="@description" /> + + @if(card != null){ + <meta name="twitter:card" content="summary_large_image" /> + <meta name="og:title" content="@title" /> + <meta name="og:description" content="@description" /> + <meta name="og:image" content="@(urlBase + card.Destination)" /> + } + </head> <body class="antialiased text-gray-600 min-h-full flex flex-col bg-gray-50"> <header class="flex-none text-sm font-medium bg-gradient-to-b from-gray-200 to-gray-100 ring-1 ring-gray-900 ring-opacity-5 shadow py-2 md:py-4"> @@ -66,7 +76,7 @@ } </div> - @foreach (IDocument document in OutputPages.GetChildrenOf(root).OnlyVisible()) + @foreach (IDocument document in OutputPages.GetChildrenOf(root).OrderBy(i => i.GetInt("Order")).OnlyVisible()) { if(string.IsNullOrWhiteSpace(document.GetTitle())) { @@ -100,7 +110,10 @@ } </nav> <article class="flex-1 min-w-0"> - <h1 class="text-gray-800 text-4xl mb-4 font-extrabold">@(Document.GetString(Keys.Title) ?? Document.GetTitle())</h1> + <header class="text-gray-800 mb-4"> + <h1 class="text-4xl font-extrabold">@(Document.GetString(Keys.Title) ?? Document.GetTitle())</h1> + @RenderSection("subheading", required: false) + </header> <div class="prose max-w-none prose-sm lg:prose lg:max-w-none 2xl:prose-xl 2xl:max-w-none text-gray-700 font-light"> @RenderBody() </div> diff --git a/docs/input/_posts.cshtml b/docs/input/_posts.cshtml deleted file mode 100644 index 735ddd2..0000000 --- a/docs/input/_posts.cshtml +++ /dev/null @@ -1,42 +0,0 @@ -<div> - @foreach (IDocument post in Document.GetChildren()) - { - IDocument topicDocument = Outputs[nameof(Archives)][$"blog/topics/{post.GetString("topic")}/index.html"]; - string excerpt = post.GetString(Statiq.Html.HtmlKeys.Excerpt); - <div> - <div class="p-3 mb-2 bg-light page-box"> - <h5><a href="@Context.GetLink(post)">@post.GetString("Title")</a></h5> - <div class="small text-black-50"> - @post.GetDateTime("Published").ToLongDateString() in - <a href="@(topicDocument.GetLink())"><span class="badge badge-light">@topicDocument.GetTitle()</span></a> - </div> - @if (!string.IsNullOrEmpty(excerpt)) - { - @Html.Raw(excerpt) - <p class="small"><a href="@Context.GetLink(post)">Read more...</a></p> - } - </div> - </div> - } - @{ - IDocument older = Document.GetDocument(Keys.Next); - IDocument newer = Document.GetDocument(Keys.Previous); - } - @if (older != null || newer != null) - { - <div class="d-flex flex-row justify-content-between"> - <div> - @if (older != null) - { - <a class="btn btn-primary" href="@Context.GetLink(older)" role="button">Older</a> - } - </div> - <div> - @if (newer != null) - { - <a class="btn btn-primary" href="@Context.GetLink(newer)" role="button">Newer</a> - } - </div> - </div> - } -</div> \ No newline at end of file diff --git a/docs/input/appendix/borders.md b/docs/input/appendix/borders.md index 36b6b02..0a83f13 100644 --- a/docs/input/appendix/borders.md +++ b/docs/input/appendix/borders.md @@ -1,5 +1,11 @@ Title: Borders Order: 2 +Description: "*Spectre.Console* makes it easy to create tables and panels with a variety of different styles of borders." +Highlights: + - Rounded + - Square + - Heavy + - And more... --- There is different built-in borders you can use for tables and panels. diff --git a/docs/input/appendix/colors.md b/docs/input/appendix/colors.md index 572bd80..d8b81d2 100644 --- a/docs/input/appendix/colors.md +++ b/docs/input/appendix/colors.md @@ -1,5 +1,9 @@ Title: Colors Order: 0 +Description: "*Spectre.Console* allows easy rendering of the standard ANSI colors of your terminal, and also supports rendering up to 24-bit colors depending on the capabilities of your terminal." +Highlights: + - Predefined common colors + - Easy syntax for inline styling --- The following is a list of the standard 8-bit colors supported in terminals. diff --git a/docs/input/appendix/emojis.md b/docs/input/appendix/emojis.md index b70ea38..fb770cf 100644 --- a/docs/input/appendix/emojis.md +++ b/docs/input/appendix/emojis.md @@ -1,5 +1,9 @@ Title: Emojis Order: 3 +Description: "For terminals that support Emojis, *Spectre.Console* supports a simple syntax for rendering emojis." +Highlights: + - ":rocket: becomes ๐" + - ":waning_gibbous_moon: becomes ๐" --- Please note that what emojis that can be used is completely up to diff --git a/docs/input/appendix/spinners.md b/docs/input/appendix/spinners.md index df50cd6..fb786e9 100644 --- a/docs/input/appendix/spinners.md +++ b/docs/input/appendix/spinners.md @@ -1,5 +1,9 @@ Title: Spinners Order: 4 +Description: "*Spectre.Console* supports over 80 different types of spinners, and allows new ones to be defined. They are used automatically with the controls" +Highlights: + - Status display + - Progress display --- For all available spinners, see https://jsfiddle.net/sindresorhus/2eLtsbey/embedded/result/ diff --git a/docs/input/appendix/styles.md b/docs/input/appendix/styles.md index 913d2e5..c437eb7 100644 --- a/docs/input/appendix/styles.md +++ b/docs/input/appendix/styles.md @@ -1,5 +1,10 @@ Title: Styles Order: 1 +Description: "*Spectre.Console* makes it easy to write text with different styles beyond colors. Depending on your terminal, it can make it easy to use styles such as" +Highlights: + - Bold, Italic, Underline, strikethrough + - Dim, Invert + - Conceal, slowblink, rapidblink --- Note that what styles that can be used is defined by the system or your terminal software, and may not appear as they should. diff --git a/docs/input/blog/_category.yaml b/docs/input/blog/_category.yaml new file mode 100644 index 0000000..c3b0f84 --- /dev/null +++ b/docs/input/blog/_category.yaml @@ -0,0 +1,15 @@ +ArchiveSources: => $"blog/posts/**/*" +ArchiveKey: Category +ArchiveKeyComparer: => StringComparer.OrdinalIgnoreCase.ToConvertingEqualityComparer() +ArchiveDestination: > + => GetInt("Index") <= 1 ? $"blog/{NormalizedPath.OptimizeFileName(GetString("GroupKey"))}/index.html" : $"blog/{NormalizedPath.OptimizeFileName(GetString("GroupKey"))}/{GetInt("Index")}.html" +ArchivePageSize: => 5 +ArchiveOrderKey: published +ArchiveOrderDescending: true +Title: Categories +ArchiveTitle: => GetString("GroupKey") +# we only show if we have a group key which means we are a category and not the index and also +# if we are the first page +Hidden: > + => doc.GetString("GroupKey") != null && doc.GetInt("Index") <= 1 ? false : true +Order: 250 \ No newline at end of file diff --git a/docs/input/blog/_directory.yaml b/docs/input/blog/_directory.yaml new file mode 100644 index 0000000..a95e4b7 --- /dev/null +++ b/docs/input/blog/_directory.yaml @@ -0,0 +1,2 @@ +Hidden: true +Order: 1000 \ No newline at end of file diff --git a/docs/input/blog/_index.yaml b/docs/input/blog/_index.yaml new file mode 100644 index 0000000..14e305b --- /dev/null +++ b/docs/input/blog/_index.yaml @@ -0,0 +1,10 @@ +Title: Recent Blog Posts +ArchiveSources: => $"blog/posts/**/*" +ArchiveDestination: > + => GetInt("Index") <= 1 ? $"blog/index.html" : $"blog/{GetInt("Index")}.html" +ArchivePageSize: => 5 +ArchiveOrderKey: Published +ArchiveOrderDescending: true +Hidden: > + => doc.GetInt("Index") == 1 ? false : true +Order: 25 diff --git a/docs/input/blog/_nextprevious.cshtml b/docs/input/blog/_nextprevious.cshtml new file mode 100644 index 0000000..8d3c159 --- /dev/null +++ b/docs/input/blog/_nextprevious.cshtml @@ -0,0 +1,27 @@ + +@inherits StatiqRazorPage<IDocument> +@model IDocument + +@{ + var older = Model.GetDocument(Keys.Next); + var newer = Model.GetDocument(Keys.Previous); +} + + +@if (older != null || newer != null) +{ + <div class="flex flex-row justify-content-between"> + <div> + @if (older != null) + { + <a class="py-0.5 px-1 mr-4 text-blue-900 bg-grey-50 border border-blue-200 hover:bg-grey-100 hover:text-blue-800 hover:border-blue-300 rounded transition-colors" href="@Context.GetLink(older)" role="button">Older</a> + } + </div> + <div> + @if (newer != null) + { + <a class="py-0.5 px-1 mr-4 text-blue-900 bg-grey-50 border border-blue-200 hover:bg-grey-100 hover:text-blue-800 hover:border-blue-300 rounded transition-colors" href="@Context.GetLink(newer)" role="button">Newer</a> + } + </div> + </div> +} \ No newline at end of file diff --git a/docs/input/blog/_posts.cshtml b/docs/input/blog/_posts.cshtml new file mode 100644 index 0000000..1456eba --- /dev/null +++ b/docs/input/blog/_posts.cshtml @@ -0,0 +1,33 @@ +@inherits StatiqRazorPage<IEnumerable<IDocument>> +@foreach (var post in Model) +{ + <div> + <h3 class="mb-0"><a href="@Context.GetLink(post)">@post.GetString("Title")</a></h3> + @{ + var author = post.GetString("Author"); + var published = post.GetDateTime("Published"); + var category = post.GetString("Category"); + } + <div class="mt-2 font-light text-xs md:text-sm"> + <span>Posted </span> + @if (published != default(DateTime)) { + <span>@published.ToLongDateString() </span> + } + @if (author != null) { + <span>by @author </span> + } + @if (category != null) { + var categoryUrl = @Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(category)}/index.html"); + <span> + to <a class="text-blue-800 underline" href="@categoryUrl"> + @category + </a> + </span> + } + + </div> + <article> + @Html.Raw(@post.GetString("Excerpt")) + </article> + </div> +} \ No newline at end of file diff --git a/docs/input/blog/category.cshtml b/docs/input/blog/category.cshtml new file mode 100644 index 0000000..b55d853 --- /dev/null +++ b/docs/input/blog/category.cshtml @@ -0,0 +1,14 @@ +@inherits StatiqRazorPage<IDocument> +@if (Document.ContainsKey(Keys.GroupKey)) +{ + @Html.Partial("_posts.cshtml", Document.GetChildren()) + @Html.Partial("_nextprevious.cshtml", Document) +} +else +{ + @foreach (var tag in Document.GetChildren().OrderByDescending(x => x.GetChildren().Count())) + { + var postCount = tag.GetChildren().Count().ToString(); + <a role="button" href="@Context.GetLink(tag)" class="badge badge-light"> @tag.GetTitle() (@postCount)</a> + } +} \ No newline at end of file diff --git a/docs/input/blog/index.cshtml b/docs/input/blog/index.cshtml new file mode 100644 index 0000000..ee5f2fb --- /dev/null +++ b/docs/input/blog/index.cshtml @@ -0,0 +1,3 @@ +@inherits StatiqRazorPage<IDocument> +@Html.Partial("_posts.cshtml", Document.GetChildren()) +@Html.Partial("_nextprevious.cshtml", Document) diff --git a/docs/input/blog/posts/2021-07-11-hello-world.md b/docs/input/blog/posts/2021-07-11-hello-world.md new file mode 100644 index 0000000..1d272b3 --- /dev/null +++ b/docs/input/blog/posts/2021-07-11-hello-world.md @@ -0,0 +1,9 @@ +Title: Hello, World +Description: To help track new releases, updates and planning for Spectre.Console, we've added a new blog to the documentation. +Published: 20210711 +Category: News +--- + +To help track new releases, updates and planning for Spectre.Console, we've added a new blog to the documentation. + +Stay tuned for upcoming information related to the 0.41 release! \ No newline at end of file diff --git a/docs/input/blog/posts/BLOG_TEMPLATE.md b/docs/input/blog/posts/BLOG_TEMPLATE.md new file mode 100644 index 0000000..22fa788 --- /dev/null +++ b/docs/input/blog/posts/BLOG_TEMPLATE.md @@ -0,0 +1,19 @@ +Title: Short title, less than 50 characters +Description: Longer description, with optional *bold* and **italic** characters. Shouldn't be TOO long but can span multiple lines. +Published: 20210710 +Category: Release Notes | News | or whatever +Excluded: true +--- + +Intro paragraph, maybe even just the description. No need for a title that's included automatically. + +## Use second level headers + +Main title will be set with h1 + +## Tasks + +1. Set title and description +2. Set proper publish date +3. Set proper category +4. Remove excluded attribute. \ No newline at end of file diff --git a/docs/input/blog/posts/_ViewStart.cshtml b/docs/input/blog/posts/_ViewStart.cshtml new file mode 100644 index 0000000..451a054 --- /dev/null +++ b/docs/input/blog/posts/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = @$"_layout.cshtml"; +} \ No newline at end of file diff --git a/docs/input/blog/posts/_layout.cshtml b/docs/input/blog/posts/_layout.cshtml new file mode 100644 index 0000000..4d23659 --- /dev/null +++ b/docs/input/blog/posts/_layout.cshtml @@ -0,0 +1,34 @@ +@{ + Layout = @"../../_layout.cshtml"; +} +@inherits StatiqRazorPage<IDocument> + +@{ + var author = Model.GetString("Author"); + var published = Model.GetDateTime("Published"); + var category = Model.GetString("Category"); +} + +@section subheading{ +<div class="mt-2 font-light text-xs md:text-sm"> + <span>Posted </span> + @if (published != default(DateTime)) { + <span>@published.ToLongDateString() </span> + } + @if (author != null) { + <span>by @author </span> + } + @if (category != null) { + <span> + to <a class="text-blue-800 underline" href="@Context.GetLink($"blog/{NormalizedPath.OptimizeFileName(@category)}/index.html")"> + @category + </a> + </span> + } + +</div> +} + + + +@RenderBody() diff --git a/docs/input/cli/commandApp.md b/docs/input/cli/commandApp.md index 4c2e09d..bf0919f 100644 --- a/docs/input/cli/commandApp.md +++ b/docs/input/cli/commandApp.md @@ -1,5 +1,6 @@ Title: CommandApp Order: 2 +Description: "**CommandApp** is the entry point for a *Spectre.Console.Cli* command line application. It is used to configure the settings and commands used for execution of the application." --- `CommandApp` is the entry point for a `Spectre.Console.Cli` command line application. It is used to configure the settings and commands used for execution of the application. Most `Spectre.Console.Cli` applications will need to specify a custom configuration using the `Configure` method. diff --git a/docs/input/cli/commands.md b/docs/input/cli/commands.md index aa56a18..6abcc46 100644 --- a/docs/input/cli/commands.md +++ b/docs/input/cli/commands.md @@ -1,5 +1,6 @@ Title: Creating Commands Order: 6 +Description: "How to create commands for *Spectre.Console.Cli*" --- Commands in `Spectre.Console.Cli` are defined by creating a class that inherits from either `Spectre.Console.Cli.Command<TSettings>` or `Spectre.Console.Cli.AsyncCommand<TSettings>`. `Command<TSettings>` must implement an `Execute` method that returns an int where as `AsyncCommand<TSettings>` must implement `ExecuteAsync` returning `Task<int>`. diff --git a/docs/input/cli/composing.md b/docs/input/cli/composing.md index 3e3a294..7c548ac 100644 --- a/docs/input/cli/composing.md +++ b/docs/input/cli/composing.md @@ -1,6 +1,8 @@ Title: Composing Commands RedirectFrom: introduction Order: 8 +Description: "The underlying philosophy behind *Spectre.Console.Cli* is to rely on the .NET type system to +declare the commands, but tie everything together via composition." --- The underlying philosophy behind `Spectre.Console.Cli` is to rely on the .NET type system to diff --git a/docs/input/cli/getting-started.md b/docs/input/cli/getting-started.md index 68db8eb..1f41be9 100644 --- a/docs/input/cli/getting-started.md +++ b/docs/input/cli/getting-started.md @@ -1,5 +1,6 @@ Title: Getting Started Order: 1 +Description: "How to get started using *Spectre.Console.Cli* to write a modern console application that follows industry conventions for command line parsing." --- `Spectre.Console.Cli` is a modern library for parsing command line arguments. While it's extremely diff --git a/docs/input/cli/index.cshtml b/docs/input/cli/index.cshtml index a35cdb6..5177459 100644 --- a/docs/input/cli/index.cshtml +++ b/docs/input/cli/index.cshtml @@ -1,5 +1,6 @@ Title: Spectre.Console.Cli -Order: 10 +Order: 80 +Description: "The command line interface for the *Spectre.Console* project." --- <p>Spectre.Console.Cli is a modern library for parsing command line arguments. While it's extremely opinionated in what it does, it tries to follow established industry conventions, and draws its inspiration from applications you use everyday.</p> diff --git a/docs/input/cli/introduction.md b/docs/input/cli/introduction.md index dd01aa3..f081069 100644 --- a/docs/input/cli/introduction.md +++ b/docs/input/cli/introduction.md @@ -1,5 +1,8 @@ Title: Introduction Order: 1 +Description: "*Spectre.Console.Cli* is a modern library for parsing command line arguments. While it's extremely +opinionated in what it does, it tries to follow established industry conventions, and draws +its inspiration from applications you use everyday." --- `Spectre.Console.Cli` is a modern library for parsing command line arguments. While it's extremely diff --git a/docs/input/cli/migration.md b/docs/input/cli/migration.md index e7a1e8c..e7a07ff 100644 --- a/docs/input/cli/migration.md +++ b/docs/input/cli/migration.md @@ -1,5 +1,6 @@ Title: Migrate from Spectre.Cli Order: 10 +Description: "Migrating from *Specte.Cli* to *Spectre.Console.Cli*" --- The functionality in `Spectre.Cli` has been moved into the `Spectre.Console` diff --git a/docs/input/cli/settings.md b/docs/input/cli/settings.md index aeb89d7..afb2514 100644 --- a/docs/input/cli/settings.md +++ b/docs/input/cli/settings.md @@ -1,5 +1,6 @@ Title: Specifying Settings Order: 5 +Description: "How to define command line argument settings for your *Spectre.Console.Cli* Commands" --- Settings for `Spectre.Console.Cli` commands are defined via classes that inherit from `CommandSettings`. Attributes are used to indicate how the parser interprets the command line arguments and create a runtime instance of the settings to be used. diff --git a/docs/input/exceptions.md b/docs/input/exceptions.md index ce7cd04..5939e43 100644 --- a/docs/input/exceptions.md +++ b/docs/input/exceptions.md @@ -1,5 +1,9 @@ Title: Exceptions -Order: 3 +Order: 40 +Description: "Exceptions aren't always readable when viewed in the terminal. You can make exception a bit more readable by using the **WriteException** method." +Highlights: + - Color coded output. + - Shorten long identifiers and paths. --- Exceptions aren't always readable when viewed in the terminal. diff --git a/docs/input/index.md b/docs/input/index.md index 415c78f..ee3d8af 100644 --- a/docs/input/index.md +++ b/docs/input/index.md @@ -1,4 +1,5 @@ Title: Welcome +Description: Spectre.Console is a .NET Standard 2.0 library that makes it easier to create beautiful console applications. Order: 0 --- diff --git a/docs/input/live/index.cshtml b/docs/input/live/index.cshtml index ad7a0d7..906e949 100644 --- a/docs/input/live/index.cshtml +++ b/docs/input/live/index.cshtml @@ -1,5 +1,6 @@ Title: Live -Order: 4 +Order: 50 +Description: Live displays continue to redraw their contents until an action is complete. --- Live displays continue to redraw their contents until an action is complete. diff --git a/docs/input/live/live-display.md b/docs/input/live/live-display.md index a3ba149..53c4e99 100644 --- a/docs/input/live/live-display.md +++ b/docs/input/live/live-display.md @@ -1,5 +1,9 @@ Title: Live Display Order: 0 +Description: "*Spectre.Console* can update arbitrary widgets in-place." +Highlights: + - Update tables or graphs with new updates. + - Create a custom progress bar that extends the existing control. --- Spectre.Console can update arbitrary widgets in-place. diff --git a/docs/input/live/progress.md b/docs/input/live/progress.md index ed6a335..0f27850 100644 --- a/docs/input/live/progress.md +++ b/docs/input/live/progress.md @@ -1,6 +1,11 @@ Title: Progress Order: 5 RedirectFrom: progress +Description: "*Spectre.Console* can display information about long running tasks in the console using progress bars." +Highlights: + - Custom styling of progress bars. + - Multiple predefined columns such as Throughput, Estimated Time Remaining, and more. + - Fallback for non-interactive consoles such as CI runners. --- Spectre.Console can display information about long running tasks in the console. diff --git a/docs/input/live/status.md b/docs/input/live/status.md index fe2a902..218c079 100644 --- a/docs/input/live/status.md +++ b/docs/input/live/status.md @@ -1,6 +1,10 @@ Title: Status Order: 10 RedirectFrom: status +Description: "*Spectre.Console* can display information about long running tasks in the console with the Status control." +Highlights: + - Custom spinner control for running tasks. + - Fallback for non-interactive consoles such as CI runners. --- Spectre.Console can display information about long running tasks in the console. diff --git a/docs/input/markup.md b/docs/input/markup.md index ad01db3..53989ab 100644 --- a/docs/input/markup.md +++ b/docs/input/markup.md @@ -1,5 +1,10 @@ Title: Markup -Order: 2 +Order: 30 +Description: The Markup class allows you to output rich text to the console. +Highlights: + - Easily add *color*. + - Add hyperlinks to for supported terminals. + - Emoji ๐ parsing. --- The `Markup` class allows you to output rich text to the console. diff --git a/docs/input/prompts/index.cshtml b/docs/input/prompts/index.cshtml index 3d4c781..d4756e1 100644 --- a/docs/input/prompts/index.cshtml +++ b/docs/input/prompts/index.cshtml @@ -1,5 +1,6 @@ Title: Prompts -Order: 5 +Order: 60 +Description: "*Spectre.Console* has multiple controls to assist in user input." --- <ul> diff --git a/docs/input/prompts/multiselection.md b/docs/input/prompts/multiselection.md index ab60050..be35e5b 100644 --- a/docs/input/prompts/multiselection.md +++ b/docs/input/prompts/multiselection.md @@ -1,5 +1,10 @@ Title: Multi Selection Order: 3 +Description: "The **MultiSelectionPrompt** can be used when you want the user to select one or many items from a provided list." +Highlights: + - Display multiple items for a user to scroll and choose from. + - Custom page sizes. + - Provide groups of selectable items. --- The `MultiSelectionPrompt` can be used when you want the user to select diff --git a/docs/input/prompts/selection.md b/docs/input/prompts/selection.md index bf5199b..531670a 100644 --- a/docs/input/prompts/selection.md +++ b/docs/input/prompts/selection.md @@ -1,5 +1,6 @@ Title: Selection Order: 1 +Description: "The **SelectionPrompt** can be used when you want the user to select a single item from a provided list." --- The `SelectionPrompt` can be used when you want the user to select diff --git a/docs/input/prompts/text.md b/docs/input/prompts/text.md index e55109a..3bd6043 100644 --- a/docs/input/prompts/text.md +++ b/docs/input/prompts/text.md @@ -1,6 +1,12 @@ Title: Text prompt Order: 0 RedirectFrom: prompt +Description: "*Spectre.Console* has multiple input functions for helping receive strongly typed input from a user." +Highlights: + - Confirmation. + - Strongly typed input. + - Input restricted to specific items. + - Secrets such as passwords or keys. --- Sometimes you want to get some input from the user, and for this diff --git a/docs/input/quick-start.md b/docs/input/quick-start.md index 73a0873..e7289d8 100644 --- a/docs/input/quick-start.md +++ b/docs/input/quick-start.md @@ -1,5 +1,6 @@ Title: Quick Start -Order: 1 +Order: 20 +Description: Getting started with *Spectre.Console* --- The fastest way of getting started using Spectre.Console is diff --git a/docs/input/sponsors.md b/docs/input/sponsors.md index ab16b3a..1970d24 100644 --- a/docs/input/sponsors.md +++ b/docs/input/sponsors.md @@ -1,5 +1,6 @@ Title: Sponsors -Order: 0 +Order: 10 +Description: The longevity of *Spectre.Console* is thanks to the support of our sponsors. --- The following people are [sponsoring](https://github.com/sponsors/patriksvensson) diff --git a/docs/input/widgets/barchart.md b/docs/input/widgets/barchart.md index 6319502..d1de4cd 100644 --- a/docs/input/widgets/barchart.md +++ b/docs/input/widgets/barchart.md @@ -1,5 +1,10 @@ Title: Bar Chart Order: 20 +Description: "Use **BarChart** to render bar charts to the console." +Highlights: + - Custom colors + - Labels + - Use your own data with a converter. --- Use `BarChart` to render bar charts to the console. diff --git a/docs/input/widgets/calendar.md b/docs/input/widgets/calendar.md index e509c24..7decf7c 100644 --- a/docs/input/widgets/calendar.md +++ b/docs/input/widgets/calendar.md @@ -1,6 +1,11 @@ ๏ปฟTitle: Calendar Order: 40 RedirectFrom: calendar +Description: "The **Calendar** is used to render a calendar to the terminal." +Highlights: + - Include highlighted events. + - Culture aware. + - Custom headers. --- The `Calendar` is used to render a calendar to the terminal. diff --git a/docs/input/widgets/canvas-image.md b/docs/input/widgets/canvas-image.md index 3db9f9a..cde9899 100644 --- a/docs/input/widgets/canvas-image.md +++ b/docs/input/widgets/canvas-image.md @@ -1,5 +1,6 @@ Title: Canvas Image Order: 70 +Description: "Use *ImageSharp* to parse images and render them as Ascii art to the console." --- To add [ImageSharp](https://github.com/SixLabors/ImageSharp) superpowers to diff --git a/docs/input/widgets/canvas.md b/docs/input/widgets/canvas.md index 5c80f2a..ee11548 100644 --- a/docs/input/widgets/canvas.md +++ b/docs/input/widgets/canvas.md @@ -1,5 +1,6 @@ Title: Canvas Order: 60 +Description: "**Canvas** is a widget that allows you to render arbitrary pixels to the console." --- `Canvas` is a widget that allows you to render arbitrary "pixels" diff --git a/docs/input/widgets/figlet.md b/docs/input/widgets/figlet.md index 345540e..c8fc881 100644 --- a/docs/input/widgets/figlet.md +++ b/docs/input/widgets/figlet.md @@ -1,6 +1,7 @@ Title: Figlet Order: 50 RedirectFrom: figlet +Description: "*Spectre.Console* can render FIGlet text by using the **FigletText** class." --- Spectre.Console can render [FIGlet](http://www.figlet.org/) text by using the `FigletText` class. diff --git a/docs/input/widgets/index.cshtml b/docs/input/widgets/index.cshtml index 3ba79f1..524423f 100644 --- a/docs/input/widgets/index.cshtml +++ b/docs/input/widgets/index.cshtml @@ -1,5 +1,6 @@ Title: Widgets -Order: 9 +Order: 70 +Description: "*Spectre.Console* supports many built-in widgets to help render beautiful output." --- <ul> diff --git a/docs/input/widgets/rule.md b/docs/input/widgets/rule.md index 6b9eef9..49edae8 100644 --- a/docs/input/widgets/rule.md +++ b/docs/input/widgets/rule.md @@ -1,6 +1,11 @@ Title: Rule Order: 30 RedirectFrom: rule +Description: "The **Rule** class is used to render a horizontal rule (line) to the terminal." +Highlights: + - Custom colors for line and title. + - Specify left, center or right aligned title. + --- The `Rule` class is used to render a horizontal rule (line) to the terminal. diff --git a/docs/input/widgets/table.md b/docs/input/widgets/table.md index cf646c2..2481dcd 100644 --- a/docs/input/widgets/table.md +++ b/docs/input/widgets/table.md @@ -1,6 +1,7 @@ Title: Table Order: 0 RedirectFrom: tables +Description: "Tables are a perfect way of displaying tabular data in a terminal. *Spectre.Console* is super smart about rendering tables and will adjust all columns to fit whatever is inside them." --- Tables are a perfect way of displaying tabular data in a terminal. diff --git a/docs/input/widgets/tree.md b/docs/input/widgets/tree.md index 0b86b2e..0fab485 100644 --- a/docs/input/widgets/tree.md +++ b/docs/input/widgets/tree.md @@ -1,5 +1,9 @@ Title: Tree Order: 10 +Description: "The **Tree** widget can be used to render hierarchical data." +Highlights: + - Custom colors and styles for guidelines. + - Include any *Spectre.Console* widgets as child nodes. --- The `Tree` widget can be used to render hierarchical data. diff --git a/docs/package-lock.json b/docs/package-lock.json index 4b25393..9d269df 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -138,12 +138,29 @@ "lodash.uniq": "^4.5.0" } }, + "@types/node": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.1.tgz", + "integrity": "sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA==", + "dev": true, + "optional": true + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/yauzl": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*" + } + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -167,6 +184,15 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -262,6 +288,12 @@ "node-releases": "^1.1.71" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -438,6 +470,15 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -494,6 +535,15 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -523,6 +573,18 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, "fast-glob": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", @@ -546,6 +608,15 @@ "reusify": "^1.0.4" } }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -604,6 +675,15 @@ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", "dev": true }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -704,6 +784,16 @@ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", "dev": true }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "ignore": { "version": "5.1.8", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", @@ -825,6 +915,12 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jpeg-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", + "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -941,6 +1037,12 @@ "picomatch": "^2.2.3" } }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, "mini-svg-data-uri": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.2.3.tgz", @@ -968,6 +1070,12 @@ "integrity": "sha512-1lM+BMLGuDfsdwf3rsgBSrxJwAZHFIrQ8YR61xIqdHo0uNKI9M52wNpHSrliZATJp51On6JD0AfRxd4YGSU0lw==", "dev": true }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "nanoid": { "version": "3.1.22", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", @@ -1096,6 +1204,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "picomatch": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", @@ -1108,6 +1222,34 @@ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, + "playwright": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.12.3.tgz", + "integrity": "sha512-eyhHvZV7dMAUltqjQsgJ9CjZM8dznzN1+rcfCI6W6lfQ7IlPvTFGLuKOCcI4ETbjfbxqaS5FKIkb1WDDzq2Nww==", + "dev": true, + "requires": { + "commander": "^6.1.0", + "debug": "^4.1.1", + "extract-zip": "^2.0.1", + "https-proxy-agent": "^5.0.0", + "jpeg-js": "^0.4.2", + "mime": "^2.4.6", + "pngjs": "^5.0.0", + "progress": "^2.0.3", + "proper-lockfile": "^4.1.1", + "proxy-from-env": "^1.1.0", + "rimraf": "^3.0.2", + "stack-utils": "^2.0.3", + "ws": "^7.4.6", + "yazl": "^2.5.1" + } + }, + "pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "dev": true + }, "postcss": { "version": "8.2.10", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz", @@ -1285,6 +1427,39 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "purgecss": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-3.1.3.tgz", @@ -1367,12 +1542,27 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -1397,6 +1587,12 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -1418,6 +1614,23 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, + "stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "string-width": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", @@ -1529,6 +1742,12 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "ws": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz", + "integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -1567,6 +1786,25 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } } } } diff --git a/docs/package.json b/docs/package.json index bbe7b1f..fb643a7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -16,6 +16,7 @@ "@tailwindcss/typography": "^0.4.0", "autoprefixer": "^10.2.5", "cross-env": "^7.0.3", + "playwright": "^1.12.3", "postcss": "^8.2.10", "postcss-cli": "^8.3.1", "tailwindcss": "^2.1.1" diff --git a/docs/src/Pipelines/SocialCardPipeline.cs b/docs/src/Pipelines/SocialCardPipeline.cs new file mode 100644 index 0000000..85a11b1 --- /dev/null +++ b/docs/src/Pipelines/SocialCardPipeline.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Logging; +using Microsoft.Playwright; +using Statiq.Common; +using Statiq.Core; +using Statiq.Web; +using Statiq.Web.Modules; +using Statiq.Web.Pipelines; + +namespace Docs.Pipelines +{ + public class SocialImages : Pipeline + { + public SocialImages() + { + Dependencies.AddRange(nameof(Inputs)); + + ProcessModules = new ModuleList + { + new GetPipelineDocuments(ContentType.Content), + + // Filter to non-archive content + new FilterDocuments(Config.FromDocument(doc => !Archives.IsArchive(doc))), + + // Process the content + new CacheDocuments + { + new AddTitle(), + new SetDestination(true), + new ExecuteIf(Config.FromSetting(WebKeys.OptimizeContentFileNames, true)) + { + new OptimizeFileName() + }, + new GenerateSocialImage(), + } + }; + + OutputModules = new ModuleList { new WriteFiles() }; + } + } + + class GenerateSocialImage : ParallelModule + { + private IPlaywright _playwright; + private IBrowser _browser; + private WebApplication _app; + + protected override async Task BeforeExecutionAsync(IExecutionContext context) + { + var builder = WebApplication.CreateBuilder(); + builder.Logging.ClearProviders(); + + builder.Services + .AddRazorPages() + .WithRazorPagesRoot("/src/SocialCards/"); + + _app = builder.Build(); + _app.MapRazorPages(); + _app.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider( + Path.Combine(builder.Environment.ContentRootPath, "src/SocialCards")), + RequestPath = "/static" + }); + + await _app.StartAsync().ConfigureAwait(false); + + _playwright = await Playwright.CreateAsync().ConfigureAwait(false); + _browser = await _playwright.Chromium.LaunchAsync().ConfigureAwait(false); + } + + protected override async Task FinallyAsync(IExecutionContext context) + { + await _browser.DisposeAsync().ConfigureAwait(false); + _playwright.Dispose(); + await _app.DisposeAsync().ConfigureAwait(false); + await base.FinallyAsync(context); + } + + protected override async Task<IEnumerable<IDocument>> ExecuteInputAsync(IDocument input, IExecutionContext context) + { + var url = _app.Urls.FirstOrDefault(u => u.StartsWith("http://")); + var page = await _browser.NewPageAsync(new BrowserNewPageOptions + { + ViewportSize = new ViewportSize { Width = 1200, Height = 618 }, + } + ); + + var title = input.GetString("Title"); + var description = input.GetString("Description"); + var highlights = input.GetList<string>("Highlights") ?? Array.Empty<string>(); + + await page.GotoAsync($"{url}/?title={title}&desc={description}&highlights={string.Join("||", highlights)}"); + var bytes = await page.ScreenshotAsync(); + + var destination = input.Destination.InsertSuffix("-social").ChangeExtension("png"); + var doc = context.CreateDocument( + input.Source, + destination, + new MetadataItems { { "DocId", input.Id }}, + context.GetContentProvider(bytes)); + + return new[] { doc }; + } + } +} \ No newline at end of file diff --git a/docs/src/SocialCards/CascadiaCodePL.woff2 b/docs/src/SocialCards/CascadiaCodePL.woff2 new file mode 100644 index 0000000..cff711d Binary files /dev/null and b/docs/src/SocialCards/CascadiaCodePL.woff2 differ diff --git a/docs/src/SocialCards/index.cshtml b/docs/src/SocialCards/index.cshtml new file mode 100644 index 0000000..c851190 --- /dev/null +++ b/docs/src/SocialCards/index.cshtml @@ -0,0 +1,120 @@ +@page +@using Markdig +@model Docs.SocialCards.SocialCardModel + +@{ + Layout = null; +} +<html> + +<head> + <link rel="stylesheet" href="static/styles.css" /> +</head> +<body> + + <div id="container"> + <div id="console"> + <div class="line"><span style="color:var(--brightBlack)">โญโ</span><span style="color:var(--folder)"></span><span style="background-color:var(--folder);color:var(--black)"> ~/spectre.console</span><span style="color:var(--folder);background-color:var(--dotnet)"></span><span style="background-color:var(--blue)"> .NET 5.0 </span><span style="color:var(--dotnet);background-color:var(--git)"></span><span style="background-color:var(--git);color:var(--background)">  main </span><span style="color:var(--git)"></span></div> + <div class="line"><span style="color:var(--brightBlack)">โฐโ</span> dotnet run</div> + <div class="line"></div> + <div class="line">โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โ โ</div> + <div class="line">โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ</div> + + <div id="title"><span style="color:var(--brightPurple)">@Model.Title</span></div> + <div id="content"> + @if (string.IsNullOrWhiteSpace(Model.Description) == false) + { + <p>@Html.Raw(Markdown.ToHtml(Model.Description))</p> + } + @if (string.IsNullOrWhiteSpace(Model.Highlights) == false) + { + <ul> + @foreach (var highlight in Model.Highlights.Split("||")) + { + <li>@Html.Raw(Markdown.ToHtml(highlight))</li> + } + </ul> + } + @if (string.IsNullOrWhiteSpace(Model.Footer) == false) + { + <div id="footer"><span style="color:var(--brightBlack)">@Html.Raw(@Markdown.ToHtml(@Model.Footer))</span></div> + } + </div> + + </div> + <svg id="logo" version="1.0" xmlns="http://www.w3.org/2000/svg" width="1270.000000pt" height="1270.000000pt" viewBox="0 0 1270.000000 1270.000000" preserveAspectRatio="xMidYMid meet"> + <metadata> + Created by potrace 1.16, written by Peter Selinger 2001-2019 + </metadata> + <g transform="translate(0.000000,1270.000000) scale(0.100000,-0.100000)" stroke="none"> + <path d="M799 10610 c-199 -48 -354 -191 -414 -383 l-25 -78 0 -3084 0 -3084 +25 -79 c45 -141 155 -270 289 -335 124 -61 -80 -57 2819 -57 l2646 0 5 -43 c3 +-23 8 -71 11 -105 13 -137 88 -334 179 -471 57 -85 187 -219 247 -254 25 -15 +76 -34 112 -43 87 -22 163 -7 246 46 120 78 195 211 234 411 l23 124 14 -55 +c63 -263 172 -511 326 -741 94 -142 229 -291 313 -348 272 -185 583 -197 750 +-30 66 67 84 109 89 215 4 90 4 91 -51 230 -108 276 -137 477 -122 868 l7 196 +77 0 c55 0 118 -11 229 -39 l154 -38 50 -84 c103 -172 221 -427 277 -599 38 +-120 70 -274 86 -412 8 -75 21 -155 29 -178 37 -106 117 -199 220 -253 51 -26 +202 -35 283 -17 83 18 193 97 268 192 157 199 256 485 286 825 11 122 6 524 +-7 583 -5 24 -1 26 62 43 64 16 67 16 80 0 39 -50 109 -215 149 -351 25 -85 +55 -174 67 -199 73 -156 261 -206 441 -117 65 32 110 70 159 135 128 169 178 +414 157 764 -8 143 -38 350 -55 376 -2 4 7 25 22 46 77 112 168 344 200 504 +l16 86 87 28 c188 60 391 170 498 269 132 122 183 230 183 383 0 71 -5 98 -24 +138 -24 52 -82 112 -138 141 -52 28 -205 30 -378 5 -80 -11 -179 -23 -220 -27 +l-75 -6 -29 56 c-33 65 -137 182 -211 236 -75 55 -156 94 -382 181 -110 43 +-221 87 -245 100 -54 27 -92 69 -125 138 -25 52 -26 59 -20 180 4 69 16 200 +26 291 52 430 53 809 5 1170 -54 405 -249 740 -569 979 -136 102 -297 190 +-419 231 l-36 12 0 433 c0 433 0 434 -25 512 -52 167 -171 292 -341 360 l-69 +28 -4215 2 c-2318 0 -4231 -3 -4251 -7z m8363 -1476 c417 -53 735 -193 962 +-423 98 -98 155 -175 210 -282 84 -160 117 -292 141 -559 28 -313 17 -684 -30 +-1025 -9 -60 -18 -164 -22 -230 -10 -208 22 -314 136 -452 76 -91 124 -118 +391 -218 307 -116 377 -155 450 -249 23 -31 41 -58 39 -60 -2 -2 -47 8 -99 21 +-131 35 -268 36 -360 3 -132 -47 -248 -116 -364 -218 -163 -143 -516 -488 +-703 -687 -350 -372 -504 -514 -701 -644 -348 -231 -878 -408 -1322 -442 -409 +-31 -796 45 -1059 208 -111 69 -249 210 -292 298 -32 65 -34 76 -33 165 1 104 +23 178 85 287 75 131 137 194 430 441 181 152 251 295 250 511 -1 152 -16 223 +-117 560 -35 117 -61 217 -58 222 3 5 20 9 38 9 55 0 217 31 261 50 53 23 103 +73 132 131 43 88 56 187 59 437 2 266 -1 258 91 292 108 40 254 21 330 -45 35 +-30 35 -32 53 -170 41 -311 106 -484 206 -546 48 -29 168 -48 381 -59 188 -10 +432 -1 548 20 76 14 206 56 266 86 64 32 122 101 144 170 15 49 17 82 12 253 +-5 198 -27 398 -52 482 -42 146 -125 221 -290 265 -57 15 -108 19 -268 19 +l-197 0 0 45 c0 120 -37 255 -82 300 -76 77 -210 5 -291 -157 -31 -60 -67 +-184 -67 -229 0 -27 -6 -34 -41 -50 -65 -29 -159 -98 -195 -144 -34 -43 -67 +-119 -79 -181 l-6 -35 -57 28 c-114 57 -270 58 -379 2 -61 -31 -70 -21 -49 54 +33 118 16 442 -29 536 -38 79 -114 84 -188 12 -68 -66 -136 -230 -137 -330 l0 +-29 -61 7 c-34 3 -93 6 -131 6 l-69 0 6 48 c14 97 56 282 84 368 155 475 486 +821 963 1008 108 42 308 94 430 110 62 9 124 17 138 20 76 11 479 5 592 -10z +m-7029 -78 c18 -8 261 -243 569 -552 582 -584 560 -559 543 -651 -6 -33 -69 +-101 -523 -557 -553 -554 -564 -564 -644 -551 -89 15 -151 110 -128 198 10 37 +65 95 463 495 l452 452 -472 473 c-414 414 -472 477 -478 510 -25 132 98 235 +218 183z m7169 -1405 c164 -57 201 -136 234 -502 37 -414 9 -486 -212 -558 +-155 -50 -298 -64 -579 -57 -249 6 -398 23 -439 50 -95 62 -177 346 -180 621 +-1 135 0 142 28 203 50 109 148 179 304 218 149 37 329 53 567 50 191 -2 216 +-4 277 -25z m-2002 -174 c95 -34 118 -52 152 -114 52 -94 63 -159 62 -368 -1 +-358 -44 -479 -187 -520 -146 -42 -612 -65 -727 -36 -153 38 -196 98 -226 316 +-16 120 -31 487 -21 527 9 35 89 121 140 151 99 58 228 76 522 73 200 -2 214 +-3 285 -29z m-1604 -443 c45 -33 67 -70 71 -121 5 -59 -25 -117 -77 -147 -35 +-21 -47 -21 -980 -24 -520 -2 -964 0 -988 3 -57 8 -116 60 -130 115 -19 75 12 +146 78 182 34 17 75 18 1017 16 974 -3 982 -3 1009 -24z m5329 -2140 c66 -7 +173 -14 237 -14 103 0 146 5 247 26 24 5 24 5 18 -64 -15 -159 -89 -371 -180 +-515 l-43 -68 -57 113 c-72 145 -160 261 -318 422 l-126 128 51 -7 c28 -3 105 +-13 171 -21z m-812 -652 c53 -41 140 -115 193 -165 96 -91 224 -231 224 -245 +0 -5 -30 -18 -67 -30 -79 -25 -305 -84 -308 -80 -1 2 -12 53 -24 113 -28 135 +-70 268 -127 402 -24 57 -44 106 -44 109 0 9 43 -20 153 -104z m-1173 -560 +c-9 -4 -271 61 -315 78 -29 11 -28 12 79 55 59 24 111 46 114 49 3 3 33 -36 +67 -87 34 -50 59 -93 55 -95z" /> + </g> + </svg> + </div> +</body> +</html> \ No newline at end of file diff --git a/docs/src/SocialCards/index.cshtml.cs b/docs/src/SocialCards/index.cshtml.cs new file mode 100644 index 0000000..d7ceac1 --- /dev/null +++ b/docs/src/SocialCards/index.cshtml.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; + +namespace Docs.SocialCards{ + public class SocialCardModel : PageModel + { + [BindProperty(Name = "title", SupportsGet = true)] + public string Title { get; set; } + + [BindProperty(Name = "desc", SupportsGet = true)] + public string Description { get; set; } + + [BindProperty(Name = "highlights", SupportsGet = true)] + public string Highlights { get; set; } + + [BindProperty(Name = "footer", SupportsGet = true)] + public string Footer { get; set; } + + private readonly ILogger<SocialCardModel> _logger; + + public SocialCardModel(ILogger<SocialCardModel> logger) + { + _logger = logger; + } + + public void OnGet() + { + } + } +} \ No newline at end of file diff --git a/docs/src/SocialCards/styles.css b/docs/src/SocialCards/styles.css new file mode 100644 index 0000000..a33c602 --- /dev/null +++ b/docs/src/SocialCards/styles.css @@ -0,0 +1,148 @@ +๏ปฟ@font-face { + font-family: 'CascadiaCodePL'; + src: url('CascadiaCodePL.woff2') format('woff2'); +} + +* { + padding:0; + margin:0; + } + + :root { + --height: 618px; + --width:1200px; + --line-height: 39px; + --padding: 20px; + --rows: calc((--var(--height) - var(--padding) * 2) / var(--line-height)); + --background: #1E2127; + --black: #000000; + --blue: #61AFEF; + --brightBlack: #5C6370; + --brightBlue: #61AFEF; + --brightCyan: #56B6C2; + --brightGreen: #98C379; + --brightPurple: #C678DD; + --brightRed: #E06C75; + --brightWhite: #FFFFFF; + --brightYellow: #D19A66; + --cyan: #56B6C2; + --foreground: #5C6370; + --green: #98C379; + --purple: #C678DD; + --red: #E06C75; + --white: #ABB2BF; + --yellow: #D19A66; + --folder: var(--yellow); + --dotnet: var(--blue); + --git: var(--green); + } + + + body{ + font-family:'CascadiaCodePL',monospace; + font-weight:400; + font-size: calc(var(--line-height) - 5px); + } + + #container { + background-color: var(--background); + color: #fff; + width: calc(var(--width) - var(--padding) * 2); + height: calc(var(--height) - var(--padding) * 2); + padding:var(--padding); + position: relative; + } + + #console{ + position: relative; + } + + .line{ + height:var(--line-height); + width:100%; + white-space: pre; + } + + #title{ + position: absolute; + left: 3ch; + top: calc(3 * var(--line-height)); + margin: 0 -3px; + padding: 0 3px; + background:var(--background); + z-index:4; + } + + #content{ + position: absolute; + left: 3ch; + top: calc(5 * var(--line-height));; + height:calc(var(--height) - 7 * var(--line-height)); + width: 53ch; + line-height:var(--line-height); + overflow-y: hidden; + } + + #content p { + margin: 0; + } + + #content p + ul { + margin-top:var(--line-height); + } + + #content strong { + color: var(--yellow); + font-weight: 400; + } + + #content em, #content i { + color: var(--blue); + font-style: normal; + } + + #content ul { + list-style: "*"; + margin-left: 1ch; + } + + #content ul li { + padding-left:1ch; + } + + + + #footer{ + position: absolute; + top: calc(var(--height) - var(--padding) - var(--line-height) * 3); + left : 3ch; + background:var(--background); + width:51ch; + z-index:4; + } + + #logo{ + height:calc(var(--line-height) * 2.5); + width:calc(var(--line-height) * 2.5); + position:absolute; + right:2ch; + top:calc(var(--padding) / 2); + fill: var(--white); + opacity:.4; + } + + #container::before { + /* fake scan lines */ + content: " "; + display: block; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06)); + z-index: 200; + background-size: 100% 4px, 5px 100%; + pointer-events: none; + } +