Skip to content

Commit

Permalink
Add markdown renderer component (#1230)
Browse files Browse the repository at this point in the history
* Add MarkdownRenderer component

* FirstOrDefault -> FirstOrOptional

* Update DiagnosticDetails
  • Loading branch information
erri120 committed Apr 17, 2024
1 parent 0f8d2e9 commit 9f39176
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ public static IEnumerable<Mod> GetEnabledMods(this Loadout loadout)
this Loadout loadout,
bool onlyEnabledMods = true) where T : AModMetadata
{
return loadout.GetModsWithMetadata<T>(onlyEnabledMods).FirstOrDefault();
return loadout.GetModsWithMetadata<T>(onlyEnabledMods).FirstOrOptional(_ => true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Reactive;
using ReactiveUI;

namespace NexusMods.App.UI.Controls.MarkdownRenderer;

public interface IMarkdownRendererViewModel : IViewModelInterface
{
/// <summary>
/// Gets or sets the contents of the renderer.
/// </summary>
public string Contents { get; set; }

/// <summary>
/// Gets the command used for opening links from Markdown.
/// </summary>
public ReactiveCommand<string, Unit> OpenLinkCommand { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Reactive;
using JetBrains.Annotations;
using ReactiveUI;

namespace NexusMods.App.UI.Controls.MarkdownRenderer;

public class MarkdownRendererDesignViewModel : AViewModel<IMarkdownRendererViewModel>, IMarkdownRendererViewModel
{
public string Contents { get; set; }

public ReactiveCommand<string, Unit> OpenLinkCommand { get; } = ReactiveCommand.Create<string>(_ => { });

public MarkdownRendererDesignViewModel() : this(DefaultContents) { }

public MarkdownRendererDesignViewModel(string contents)
{
Contents = contents;
}

// From https://jaspervdj.be/lorem-markdownum/
[LanguageInjection("markdown")]
private const string DefaultContents =
"""
# Quid nostro

## Velox tot frugum accipe

Lorem markdownum sacros si Iovis aquarum, oreris bene inmurmurat arborei
propulsa labori invidiosa, sic tibi sic: tumulis. Pectoris ait plectrum fregit
aegram. Cum *legit urit* nec solet corpora loquebatur cur, in vivaque quasque
corpus **sagittas Numam** Lucifer mentesque, **falsa**. Vult plagis sospite
veneni prodiga ratione, currus malus! Et sinat mersaeque fletque cycnus
auxiliaris, sum **quid frondentis** sensit.

1. Moneo ora equos per monstro o foedera
2. Confusura veneni lacertis pisce inmedicabile quid tenuaverat
3. Ardere una quam paciscor alimenta liber
4. Captivarum Venus
5. Nunc iphis Orion aethera genitore doleas pro

Insula illa optime in admonita exigit, clausit sua aut paelicis potiunda ipsius
canes falsisque esset donare. In mea ima loquor, superest vocas densa cognoscere
trepidum inque, restagnantis. Auras est accipiunt erant init turpi tenet isto
voce teretesque facta, quae dederat vultus milite primo. Adspicit ignare
saxumque, tenet fuga male tabuerint umbram *pariterque* nuda vinctumque pugna,
exercita.

## Et tumida

Ut abolere turba dignus, pone respondere comis credo moenia et Cragon nondum
pallenti. Urbem Thracum medii praeclusaque vocanti et senemque per? Deo
genuumque pater, in mihi ruborem: aut mutavit terris removi refert atque
indignave veros, in, promittet! Foeda tempora lux Pholus sit Ligurum quis
[cacumen tamen](http://et.io/cepit.html): hanc.

- Fuisti aptas
- Furibunda arbore passus vulnera quinque Nox menti
- Et gerebat praedae ut duxerat memoranda per
- Nuper Vidi non crines non munusque accusasse
- Trahit opibus vellet rudis

## Habendi ignibus

Ille artus, alma deus est vetus, totidem deprensum arbor lacrimaeque? Illis
Canopo subit lucis tradit [ab](http://www.et-flore.com/pars-spirat.php) certis
mortemque seraque in, **o** vestris omine. *Validum* Lapithaeae, ita orbem dum
praesagaque, dictis, iam disci errore coercuit sit modo Hylactor! Rogat
*iacentes et quaeque* fulva, sertis unguibus quoque possis. Suo Rhodopeius
madefient, mitissima despectus diversa stratis.

1. Diomede aquis
2. Regna mea mota sic usae tu maior
3. Nec hic adunci

Sed esse, prima picum omnes nam patrii do resedit; petebat sed. Amores auras,
potentia subsidunt auras nec: dicar cum dimotis. Fuit Thestias: quam sed hunc
querella erat in inposita. Patuit nomen multi possum quosque erratica patefecit
laudemur: umbrae praedae locus caecis siquidem et cuncti.

""";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<reactive:ReactiveUserControl
x:TypeArguments="local:IMarkdownRendererViewModel"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactive="http://reactiveui.net"
xmlns:local="clr-namespace:NexusMods.App.UI.Controls.MarkdownRenderer"
xmlns:md="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia"
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="NexusMods.App.UI.Controls.MarkdownRenderer.MarkdownRendererView">

<Design.DataContext>
<local:MarkdownRendererDesignViewModel />
</Design.DataContext>

<!--
NOTE(erri120): This control can only be styled directly, not through classes.
https://github.com/whistyun/Markdown.Avalonia/wiki/How-to-customise-style
-->
<md:MarkdownScrollViewer x:Name="MarkdownScrollViewer">
<md:MarkdownScrollViewer.Styles>
<Style Selector="ctxt|CTextBlock">
<Setter Property="FontFamily" Value="{StaticResource FontBodyRegular}" />
<Setter Property="Foreground" Value="{StaticResource NeutralSubduedBrush}" />
</Style>

<Style Selector="ctxt|CHyperlink">
<Setter Property="FontFamily" Value="{StaticResource FontBodyRegular}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading1">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading2">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading3">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading4">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading5">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading6">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>
</md:MarkdownScrollViewer.Styles>
</md:MarkdownScrollViewer>

</reactive:ReactiveUserControl>

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Reactive.Disposables;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace NexusMods.App.UI.Controls.MarkdownRenderer;

public partial class MarkdownRendererView : ReactiveUserControl<IMarkdownRendererViewModel>
{
public MarkdownRendererView()
{
InitializeComponent();

this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.Contents, view => view.MarkdownScrollViewer.Markdown)
.DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.OpenLinkCommand, view => view.MarkdownScrollViewer.Engine.HyperlinkCommand)
.DisposeWith(disposables);
});
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Reactive;
using JetBrains.Annotations;
using NexusMods.CrossPlatform.Process;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace NexusMods.App.UI.Controls.MarkdownRenderer;

[UsedImplicitly]
public class MarkdownRendererViewModel : AViewModel<IMarkdownRendererViewModel>, IMarkdownRendererViewModel
{
[Reactive] public string Contents { get; set; } = string.Empty;

public ReactiveCommand<string, Unit> OpenLinkCommand { get; }

public MarkdownRendererViewModel(IOSInterop osInterop)
{
OpenLinkCommand = ReactiveCommand.CreateFromTask<string>(async url =>
{
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return;
await Task.Run(() =>
{
osInterop.OpenUrl(uri);
});
});
}
}
6 changes: 6 additions & 0 deletions src/NexusMods.App.UI/NexusMods.App.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,12 @@
<Compile Update="Pages\Diff\ApplyDiff\ApplyDiffDesignViewModel.cs">
<DependentUpon>IApplyDiffViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Controls\MarkdownRenderer\MarkdownRendererViewModel.cs">
<DependentUpon>IMarkdownRendererViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Controls\MarkdownRenderer\MarkdownRendererDesignViewModel.cs">
<DependentUpon>IMarkdownRendererViewModel.cs</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using System.Reactive;
using NexusMods.Abstractions.Diagnostics;
using NexusMods.App.UI.Controls.MarkdownRenderer;
using NexusMods.App.UI.Windows;
using NexusMods.App.UI.WorkspaceSystem;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.Diagnostics;

public class DiagnosticDetailsDesignViewModel : APageViewModel<IDiagnosticDetailsViewModel>, IDiagnosticDetailsViewModel
{
public string Details { get; } = "This is an example diagnostic details, lots of stuff here.";
public DiagnosticSeverity Severity { get; } = DiagnosticSeverity.Critical;

private const string Details = "This is an example diagnostic details, lots of stuff here.";
public DiagnosticSeverity Severity => DiagnosticSeverity.Critical;

public IMarkdownRendererViewModel MarkdownRendererViewModel => new MarkdownRendererDesignViewModel(Details);

public DiagnosticDetailsDesignViewModel() : base(new DesignWindowManager()) { }

public ReactiveCommand<string, Unit> MarkdownOpenLinkCommand { get; } = ReactiveCommand.Create<string>(_ => { });
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using NexusMods.Abstractions.Diagnostics;
using NexusMods.App.UI.Windows;
using NexusMods.App.UI.Controls.MarkdownRenderer;
using NexusMods.App.UI.WorkspaceSystem;
using NexusMods.CrossPlatform.Process;

namespace NexusMods.App.UI.Pages.Diagnostics;

Expand All @@ -24,9 +23,10 @@ public class DiagnosticDetailsPageFactory : APageFactory<IDiagnosticDetailsViewM
public override IDiagnosticDetailsViewModel CreateViewModel(DiagnosticDetailsPageContext context)
{
return new DiagnosticDetailsViewModel(
ServiceProvider.GetRequiredService<IOSInterop>(),
WindowManager,
ServiceProvider.GetRequiredService<IDiagnosticWriter>(),
context.Diagnostic);
WindowManager,
ServiceProvider.GetRequiredService<IDiagnosticWriter>(),
ServiceProvider.GetRequiredService<IMarkdownRendererViewModel>(),
context.Diagnostic
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
xmlns:reactiveUi="http://reactiveui.net"
xmlns:diagnostics="clr-namespace:NexusMods.App.UI.Pages.Diagnostics"
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
xmlns:md="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia"
xmlns:ctxt="clr-namespace:ColorTextBlock.Avalonia;assembly=ColorTextBlock.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="NexusMods.App.UI.Pages.Diagnostics.DiagnosticDetailsView">

Expand Down Expand Up @@ -36,55 +34,7 @@

<Border x:Name="HorizontalLine" Height="1" />

<!--
NOTE(erri120): This control can only be styled directly, not through classes.
If this needs to be re-used, make a wrapper control out of it.
https://github.com/whistyun/Markdown.Avalonia/wiki/How-to-customise-style
-->
<md:MarkdownScrollViewer x:Name="MarkdownScrollViewer">
<md:MarkdownScrollViewer.Styles>
<Style Selector="ctxt|CTextBlock">
<Setter Property="FontFamily" Value="{StaticResource FontBodyRegular}" />
<Setter Property="Foreground" Value="{StaticResource NeutralSubduedBrush}" />
</Style>

<Style Selector="ctxt|CHyperlink">
<Setter Property="FontFamily" Value="{StaticResource FontBodyRegular}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading1">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading2">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading3">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading4">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading5">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>

<Style Selector="ctxt|CTextBlock.Heading6">
<Setter Property="FontFamily" Value="{StaticResource FontHeadlinesSemiBold}" />
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
</Style>
</md:MarkdownScrollViewer.Styles>
</md:MarkdownScrollViewer>
<reactiveUi:ViewModelViewHost x:Name="MarkdownRendererViewModelViewHost"/>
</StackPanel>
</Border>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.ReactiveUI;
using Markdown.Avalonia.Utils;
using JetBrains.Annotations;
using NexusMods.Abstractions.Diagnostics;
using NexusMods.App.UI.Resources;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.Diagnostics;

[UsedImplicitly]
public partial class DiagnosticDetailsView : ReactiveUserControl<IDiagnosticDetailsViewModel>
{
public DiagnosticDetailsView()
Expand All @@ -27,6 +28,8 @@ public DiagnosticDetailsView()

private void InitializeData(IDiagnosticDetailsViewModel vm)
{
MarkdownRendererViewModelViewHost.ViewModel = vm.MarkdownRendererViewModel;

switch (vm.Severity)
{
case DiagnosticSeverity.Suggestion:
Expand Down Expand Up @@ -55,8 +58,5 @@ private void InitializeData(IDiagnosticDetailsViewModel vm)
SeverityTitleTextBlock.Text = Language.DiagnosticDetailsView_SeverityTitle_HIDDEN.ToUpperInvariant();
break;
}

MarkdownScrollViewer.Engine.HyperlinkCommand = vm.MarkdownOpenLinkCommand;
MarkdownScrollViewer.Markdown = vm.Details;
}
}
Loading

0 comments on commit 9f39176

Please sign in to comment.