-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from YumeChan-DT/feature/docs
Implement MoltenObsidian-flavoured plugin documentation
- Loading branch information
Showing
19 changed files
with
519 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<component name="ProjectRunConfigurationManager"> | ||
<configuration default="false" name="YumeChan NetRunner" type="LaunchSettings" factoryName=".NET Launch Settings Profile"> | ||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/src/YumeChan.NetRunner/YumeChan.NetRunner.csproj" /> | ||
<option name="LAUNCH_PROFILE_TFM" value="net6.0" /> | ||
<option name="LAUNCH_PROFILE_NAME" value="YumeChan.NetRunner" /> | ||
<option name="USE_EXTERNAL_CONSOLE" value="0" /> | ||
<option name="USE_MONO" value="0" /> | ||
<option name="RUNTIME_ARGUMENTS" value="" /> | ||
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" /> | ||
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" /> | ||
<option name="SEND_DEBUG_REQUEST" value="1" /> | ||
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" /> | ||
<method v="2"> | ||
<option name="Build" /> | ||
</method> | ||
</configuration> | ||
</component> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
src/YumeChan.NetRunner.Plugins/Services/Docs/PluginDocsLoader.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Reflection; | ||
using Nodsoft.MoltenObsidian.Vault; | ||
using Nodsoft.MoltenObsidian.Vaults.FileSystem; | ||
using YumeChan.Core.Config; | ||
using YumeChan.Core.Services.Plugins; | ||
using YumeChan.PluginBase; | ||
using YumeChan.PluginBase.Infrastructure; | ||
|
||
namespace YumeChan.NetRunner.Plugins.Services.Docs; | ||
|
||
/// <summary> | ||
/// <p>Provides a service to load a plugin's documentation.</p> | ||
/// | ||
/// <p> | ||
/// Documentation is loaded from the plugin's directory, | ||
/// and is expected to be in the form of a single or multiple Markdown files. | ||
/// | ||
/// A Tree structure is created from the Markdown files found recursively in the plugin's <c>/docs</c> directory. | ||
/// </p> | ||
/// | ||
/// </summary> | ||
public sealed class PluginDocsLoader | ||
{ | ||
private readonly ICoreProperties _coreProperties; | ||
private readonly PluginsLoader _pluginsLoader; | ||
|
||
public PluginDocsLoader(ICoreProperties coreProperties, PluginsLoader pluginsLoader) | ||
{ | ||
_coreProperties = coreProperties; | ||
_pluginsLoader = pluginsLoader; | ||
} | ||
|
||
private readonly Dictionary<string, IVault?> _vaults = new(); | ||
|
||
/// <summary> | ||
/// Gets a <see cref="IVault"/> for the specified plugin. | ||
/// </summary> | ||
/// <param name="pluginName">The internal name of the plugin to get the vault for.</param> | ||
/// <returns>The vault for the specified plugin.</returns> | ||
/// <exception cref="ArgumentException">Thrown if the specified plugin does not exist.</exception> | ||
public IVault? GetVault(string pluginName) | ||
{ | ||
// First get from cache. | ||
if (_vaults.TryGetValue(pluginName, out IVault? vault)) | ||
{ | ||
return vault; | ||
} | ||
|
||
// Then try to instantiate from plugin's assets. | ||
|
||
// First. Does this plugin even exist? | ||
if (!_pluginsLoader.PluginManifests.TryGetValue(pluginName, out _)) | ||
{ | ||
throw new ArgumentException($"Plugin '{pluginName}' does not exist.", nameof(pluginName)); | ||
} | ||
|
||
// Then, do we have a PluginDocsAttribute? | ||
Type pluginType = pluginName.GetType(); | ||
|
||
PluginDocsAttribute? attribute = pluginType.GetCustomAttributes<PluginDocsAttribute>().FirstOrDefault() | ||
?? pluginType.Assembly.GetCustomAttributes<PluginDocsAttribute>().FirstOrDefault(); | ||
|
||
if (attribute is { Enabled: false }) | ||
{ | ||
// No, we don't. Cache the result and return null. | ||
return _vaults[pluginName] = null; | ||
} | ||
|
||
// Yes, we do. Create a new FileSystemVault. | ||
// Get the path to the plugin's docs directory. | ||
string pluginDirectory = Path.Join(_coreProperties.Path_Plugins, pluginName, attribute?.Path ?? PluginDocsAttribute.DefaultPath); | ||
|
||
// Create a new FileSystemVault, cache it, and return it. | ||
return _vaults[pluginName] = FileSystemVault.FromDirectory(new(pluginDirectory)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
@page "/docs" | ||
@page "/docs/{PluginName}/{*PathSlug}" | ||
@layout DocsLayout | ||
|
||
@using YumeChan.NetRunner.Plugins.Services.Docs | ||
@using Nodsoft.MoltenObsidian.Vault | ||
@using Nodsoft.MoltenObsidian.Blazor | ||
@using Nodsoft.MoltenObsidian.Blazor.Helpers | ||
@using Nodsoft.MoltenObsidian.Blazor.Templates | ||
@using YumeChan.NetRunner.Shared.Docs | ||
@using System.IO | ||
|
||
@inject PluginDocsLoader PluginDocsLoader | ||
|
||
<div class="page mt-xl-3"> | ||
<DocsSidebar Vault="@_vault" SelectedPlugin="@PluginName" /> | ||
|
||
<main> | ||
<article class="content px-4 my-3"> | ||
@BuildBreadcrumb(PathSlug) | ||
|
||
@if (PluginName is null or "" && PathSlug is null or "") | ||
{ | ||
|
||
} | ||
@* Loading *@ | ||
else if (_vault is null && _loadingError is null) | ||
{ | ||
<h3 class="text-info">Loading...</h3> | ||
} | ||
@* No docs found *@ | ||
else if (_loadingError is DirectoryNotFoundException || _vault?.Files.Count is 0) | ||
{ | ||
<h3 class="text-warning">No docs found.</h3> | ||
} | ||
@* Error handling *@ | ||
else if (_loadingError is not null) | ||
{ | ||
<h3 class="text-danger">Error loading plugin docs: <small>@_loadingError.Message</small></h3> | ||
} | ||
else | ||
{ | ||
<ObsidianVaultDisplay @ref="@_vaultDisplay" Vault="@_vault" BasePath="@_basePath" CurrentPath="@PathSlug"> | ||
<NotFound> | ||
<h3 class="text-warning">Not Found</h3> | ||
</NotFound> | ||
|
||
<FoundIndexNote>@FoundNote.Render(new(context.Note, context.DisplayOptions))</FoundIndexNote> | ||
</ObsidianVaultDisplay> | ||
} | ||
</article> | ||
</main> | ||
</div> | ||
|
||
@code { | ||
#nullable enable | ||
|
||
[Parameter] | ||
public string PluginName { get; set; } = string.Empty; | ||
|
||
[Parameter] | ||
public string? PathSlug { get; set; } | ||
|
||
private IVault? _vault; | ||
private string _basePath = string.Empty; | ||
|
||
private bool _loading; | ||
Check warning on line 67 in src/YumeChan.NetRunner/Pages/Docs/DocsBrowser.razor GitHub Actions / build-debug
|
||
|
||
private Exception? _loadingError; | ||
private ObsidianVaultDisplay _vaultDisplay = new(); | ||
|
||
protected override async Task OnParametersSetAsync() | ||
{ | ||
_loadingError = null; | ||
await base.OnParametersSetAsync(); | ||
|
||
// Edge case: if both parameters are null, don't load anything, and load the index page. | ||
if (PluginName is null or "" && PathSlug is null or "") | ||
{ | ||
return; | ||
} | ||
|
||
try | ||
{ | ||
_vault = PluginDocsLoader.GetVault(PluginName) ?? throw new($"No vault found for plugin '{PluginName}'."); | ||
Check warning on line 85 in src/YumeChan.NetRunner/Pages/Docs/DocsBrowser.razor GitHub Actions / build-debug
|
||
_basePath = $"/docs/{PluginName}/"; | ||
} | ||
catch (DirectoryNotFoundException e) | ||
{ | ||
_loadingError = e; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Builds a Bootstrap breadcrumb using a slash-separated path string. | ||
/// </summary> | ||
/// <param name="path">The slash-separated path string.</param> | ||
/// <returns>The RenderFragment for the breadcrumb.</returns> | ||
RenderFragment BuildBreadcrumb(string? path) => __builder => | ||
{ | ||
path ??= string.Empty; | ||
|
||
List<string> paths = new() { "." }; | ||
paths.AddRange(path.Split('/')); | ||
|
||
<ul class="breadcrumb px-3"> | ||
@for (int i = 0; i < paths.Count; i++) | ||
{ | ||
if (i is 0) | ||
{ | ||
if (paths is { Count: 1 } or [.., ""]) | ||
{ | ||
// Render active home link | ||
<li aria-current="page" class="breadcrumb-item active">~</li> | ||
break; | ||
} | ||
|
||
// Render inactive home link | ||
<li class="breadcrumb-item"> | ||
<a href="">~</a> | ||
</li> | ||
|
||
continue; | ||
} | ||
|
||
string pathName = paths[i]; | ||
|
||
|
||
if (i < paths.Count - 1) | ||
{ | ||
string pathUrl = $"{string.Join("/", paths.Take(i + 1))}"; | ||
|
||
// Inactive breadcrumb item with link | ||
<li class="breadcrumb-item"> | ||
<a href="@pathUrl">@pathName</a> | ||
</li> | ||
} | ||
else | ||
{ | ||
// Active breadcrumb item without link | ||
<li aria-current="page" class="breadcrumb-item active">@pathName</li> | ||
} | ||
} | ||
</ul> | ||
}; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.page { | ||
position: relative; | ||
display: flex; | ||
flex-direction: column; | ||
|
||
@media (min-width: 641px) { | ||
flex-direction: row; | ||
} | ||
} | ||
|
||
main { | ||
flex-grow: 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
@inherits CommonSiteLayout | ||
|
||
<div class="container-fluid" style="margin-top: 4rem !important"> | ||
<div class="page"> | ||
<header> | ||
<Navbar CurrentUri="@CurrentUri" /> | ||
</header> | ||
|
||
<main role="main"> | ||
@Body | ||
</main> | ||
</div> | ||
</div> | ||
|
||
<Footer /> | ||
|
||
@code { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
.page { | ||
position: relative; | ||
display: flex; | ||
flex-direction: column; | ||
|
||
@media (min-width: 641px) { | ||
flex-direction: row; | ||
} | ||
} | ||
|
||
main { | ||
flex: 1; | ||
} |
Oops, something went wrong.