mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-07-15 15:19:57 +00:00
* Setup wiki files deploy * Create wiki view (Closes #1118) --------- Co-authored-by: Alexandru Macocian <amacocian@microsoft.com>
This commit is contained in:
@@ -40,6 +40,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
|
||||
@@ -35,6 +35,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v5
|
||||
|
||||
@@ -365,3 +365,5 @@ MigrationBackup/
|
||||
FodyWeavers.xsd
|
||||
|
||||
.idea
|
||||
|
||||
Daybreak/wwwroot/wiki/*
|
||||
|
||||
+1
-1
Submodule Daybreak.wiki updated: ee41885ab1...e8079d1c4a
@@ -329,6 +329,7 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
viewProducer.RegisterView<ScreenSelectorView, ScreenSelectorViewModel>();
|
||||
viewProducer.RegisterView<UModManagementView, UModManagementViewModel>();
|
||||
viewProducer.RegisterView<TradeNotificationView, TradeNotificationViewModel>();
|
||||
viewProducer.RegisterView<WikiView, WikiViewModel>();
|
||||
}
|
||||
|
||||
public override void RegisterStartupActions(IStartupActionProducer startupActionProducer)
|
||||
@@ -425,8 +426,9 @@ public class ProjectConfiguration : PluginConfigurationBase
|
||||
menuServiceProducer.CreateIfNotExistCategory("Daybreak")
|
||||
//TODO: Implement Notifications view
|
||||
//.RegisterButton("Notifications", "Open notifications view", sp => { })
|
||||
.RegisterButton("Manage Plugins", "Open plugins view", sp => sp.GetRequiredService<ViewManager>().ShowView<PluginsView>())
|
||||
.RegisterButton("Manage version", "Open version manager", sp => sp.GetRequiredService<ViewManager>().ShowView<VersionManagementView>());
|
||||
.RegisterButton("Manage Plugins", "Open plugins view", sp => sp.GetRequiredService<IViewManager>().ShowView<PluginsView>())
|
||||
.RegisterButton("Manage version", "Open version manager", sp => sp.GetRequiredService<IViewManager>().ShowView<VersionManagementView>())
|
||||
.RegisterButton("Help", "Open Daybreak wiki", sp => sp.GetRequiredService<IViewManager>().ShowView<WikiView>((nameof(WikiView.Page), "Home")));
|
||||
menuServiceProducer.CreateIfNotExistCategory("Trade")
|
||||
.RegisterButton("Alerts", "Open trade alerts manager", sp => sp.GetRequiredService<IViewManager>().ShowView<TradeAlertsView>())
|
||||
.RegisterButton("Kamadan", "Open kamadan trade chat", sp => sp.GetRequiredService<IViewManager>().ShowView<TradeChatView>((nameof(TradeChatView.Source), nameof(TraderSource.Kamadan))))
|
||||
|
||||
@@ -84,10 +84,24 @@
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" />
|
||||
<PackageReference Include="NAudio" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Daybreak.Shared\Daybreak.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Copy Daybreak.wiki to wwwroot/wiki for both Debug and Release builds -->
|
||||
<PropertyGroup>
|
||||
<WikiSourcePath>..\Daybreak.wiki</WikiSourcePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<WikiFiles Include="$(WikiSourcePath)\**\*.*" Exclude="$(WikiSourcePath)\.git\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyWikiToWwwroot" BeforeTargets="BeforeBuild">
|
||||
<Message Importance="high" Text="📚 Copying Daybreak.wiki to wwwroot/wiki" />
|
||||
<Copy SourceFiles="@(WikiFiles)" DestinationFiles="@(WikiFiles->'wwwroot\wiki\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
@@ -110,6 +124,7 @@
|
||||
<UpToDateCheckInput Include="..\Daybreak.API\**\*.cs" />
|
||||
<UpToDateCheckInput Include="..\Daybreak.7ZipExtractor\**\*.cs" />
|
||||
<UpToDateCheckInput Include="..\Daybreak.Installer\**\*.cs" />
|
||||
<UpToDateCheckInput Include="..\Daybreak.wiki\**\*.*" Exclude="..\Daybreak.wiki\.git\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Daybreak.Utils;
|
||||
|
||||
public static class WebRootUtil
|
||||
{
|
||||
public static string GetWebRootPath()
|
||||
{
|
||||
var releasePath = Path.Combine(AppContext.BaseDirectory, "wwwroot");
|
||||
if (Directory.Exists(releasePath))
|
||||
{
|
||||
return releasePath;
|
||||
}
|
||||
|
||||
var debugPath = Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "wwwroot");
|
||||
if (Directory.Exists(debugPath))
|
||||
{
|
||||
return debugPath;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Could not find web root folder");
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Notifications.Handlers;
|
||||
@@ -104,6 +105,15 @@ public sealed class AppViewModel
|
||||
this.CloseNavigationMenu,
|
||||
this.ToggleNavigationMenu
|
||||
);
|
||||
this.blazorHostWindow.PreviewKeyUp += this.BlazorHostWindow_PreviewKeyDown;
|
||||
}
|
||||
|
||||
private void BlazorHostWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key is Key.F1)
|
||||
{
|
||||
this.viewManager.ShowView<WikiView>((nameof(WikiView.Page), "Home"));
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask InitializeApp(IJSRuntime jsRuntime)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<div class="wiki-container">
|
||||
<nav class="wiki-toc backdrop-panel">
|
||||
<h3>Contents</h3>
|
||||
<ul>
|
||||
@foreach (var p in this.ViewModel.Pages)
|
||||
{
|
||||
<li class="@(p == this.ViewModel.CurrentPage ? "active" : "")">
|
||||
<a href="/wiki/@p">@p</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
<div id="wiki-content" class="wiki-content backdrop-panel"></div>
|
||||
</div>
|
||||
|
||||
@page "/wiki/{Page}"
|
||||
@inherits ViewBase<WikiView, WikiViewModel>
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string? Page { get; set; }
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
var filePath = $"wiki/{this.Page}.md";
|
||||
await this.JSRuntime.InvokeVoidAsync("wikiRenderer.render", filePath, "wiki-content");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Daybreak.Utils;
|
||||
using System.Extensions;
|
||||
using System.IO;
|
||||
using TrailBlazr.ViewModels;
|
||||
|
||||
namespace Daybreak.Views;
|
||||
|
||||
public sealed class WikiViewModel : ViewModelBase<WikiViewModel, WikiView>
|
||||
{
|
||||
public string? CurrentPage { get; private set; }
|
||||
public List<string> Pages { get; } = [];
|
||||
|
||||
public override ValueTask ParametersSet(WikiView view, CancellationToken cancellationToken)
|
||||
{
|
||||
this.CurrentPage = view.Page;
|
||||
this.Pages.ClearAnd().AddRange(LoadPages());
|
||||
return base.ParametersSet(view, cancellationToken);
|
||||
}
|
||||
|
||||
private static IEnumerable<string> LoadPages()
|
||||
{
|
||||
var webRoot = WebRootUtil.GetWebRootPath();
|
||||
var wikiPath = Path.Combine(webRoot, "wiki");
|
||||
return Directory.EnumerateFiles(wikiPath, "*.md")
|
||||
.Select(Path.GetFileNameWithoutExtension)
|
||||
.OfType<string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
.wiki-container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wiki-toc {
|
||||
order: 1;
|
||||
width: 220px;
|
||||
min-width: 220px;
|
||||
padding: 1rem;
|
||||
overflow-y: auto;
|
||||
border-left: 1px solid var(--neutral-stroke-rest);
|
||||
}
|
||||
|
||||
.wiki-toc h3 {
|
||||
margin: 0 0 1rem 0;
|
||||
font-size: 1.1rem;
|
||||
color: var(--neutral-foreground-rest);
|
||||
}
|
||||
|
||||
.wiki-toc ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.wiki-toc li {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.wiki-toc li a {
|
||||
display: block;
|
||||
padding: 0.4rem 0.6rem;
|
||||
color: var(--neutral-foreground-rest);
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.wiki-toc li a:hover {
|
||||
background: var(--neutral-fill-rest);
|
||||
}
|
||||
|
||||
.wiki-toc li.active a {
|
||||
background: var(--accent-fill-rest);
|
||||
color: var(--accent-foreground-cut-rest);
|
||||
}
|
||||
|
||||
.wiki-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
color: var(--neutral-foreground-rest);
|
||||
line-height: 1.6;
|
||||
padding: 0px 1rem 0px 1rem;
|
||||
}
|
||||
|
||||
.wiki-content ::deep h1,
|
||||
.wiki-content ::deep h2,
|
||||
.wiki-content ::deep h3 {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.wiki-content ::deep h1 {
|
||||
font-size: 2rem;
|
||||
border-bottom: 1px solid var(--neutral-stroke-rest);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.wiki-content ::deep a {
|
||||
color: var(--accent-fill-rest);
|
||||
}
|
||||
|
||||
.wiki-content ::deep code {
|
||||
background: var(--neutral-fill-rest);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.wiki-content ::deep pre {
|
||||
background: var(--neutral-fill-rest);
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.wiki-content ::deep blockquote {
|
||||
border-left: 4px solid var(--accent-fill-rest);
|
||||
margin: 1rem 0;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--neutral-fill-rest);
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="_framework/blazor.webview.js"></script>
|
||||
<script src="deps/marked.js/15.0.12/marked.min.js"></script>
|
||||
<script src="js/wiki-renderer.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,95 @@
|
||||
window.wikiRenderer = {
|
||||
render: async function (filePath, targetId) {
|
||||
const element = document.getElementById(targetId);
|
||||
if (!element) {
|
||||
console.error('wiki-renderer: Element not found:', targetId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof marked === 'undefined') {
|
||||
console.error('wiki-renderer: marked.js not loaded');
|
||||
element.innerHTML = '<p>Markdown renderer not loaded.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(filePath);
|
||||
if (!response.ok) {
|
||||
element.innerHTML = '<p>Page not found.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const markdown = await response.text();
|
||||
let html = marked.parse(markdown);
|
||||
|
||||
// Rewrite relative wiki links to local wiki paths
|
||||
html = this.rewriteWikiLinks(html);
|
||||
|
||||
// Rewrite relative image paths to absolute wiki paths
|
||||
html = this.rewriteImagePaths(html);
|
||||
|
||||
element.innerHTML = html;
|
||||
|
||||
// Add IDs to headings for anchor navigation
|
||||
this.addHeadingIds(element);
|
||||
|
||||
// Add click handler for anchor links to prevent Blazor interception
|
||||
this.setupAnchorLinks(element);
|
||||
} catch (error) {
|
||||
console.error('wiki-renderer: Failed to load markdown:', error);
|
||||
element.innerHTML = '<p>Failed to load page.</p>';
|
||||
}
|
||||
},
|
||||
|
||||
addHeadingIds: function (container) {
|
||||
const headings = container.querySelectorAll('h1, h2, h3, h4');
|
||||
headings.forEach(heading => {
|
||||
if (!heading.id) {
|
||||
// Generate ID from heading text (same logic as typical markdown parsers)
|
||||
const id = heading.textContent
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^\w\s-]/g, '')
|
||||
.replace(/\s+/g, '-');
|
||||
heading.id = id;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setupAnchorLinks: function (container) {
|
||||
const anchorLinks = container.querySelectorAll('a[href^="#"]');
|
||||
anchorLinks.forEach(link => {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const targetId = link.getAttribute('href').substring(1);
|
||||
const targetElement = document.getElementById(targetId);
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
rewriteWikiLinks: function (html) {
|
||||
// Handle relative wiki links (e.g., href="PageName" or href="PageName.md")
|
||||
// Convert to /wiki/PageName (stripping .md extension if present)
|
||||
const relativeWikiPattern = /href="(?!http|\/|#)([^"]+)"/g;
|
||||
html = html.replace(relativeWikiPattern, (match, pageName) => {
|
||||
// Remove .md extension if present
|
||||
const cleanName = pageName.replace(/\.md$/i, '');
|
||||
return `href="/wiki/${cleanName}"`;
|
||||
});
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
rewriteImagePaths: function (html) {
|
||||
// Rewrite relative image src paths to absolute wiki paths
|
||||
// src="assets/image.png" -> src="/wiki/assets/image.png"
|
||||
const relativeImagePattern = /src="(?!http|\/|data:)([^"]+)"/g;
|
||||
html = html.replace(relativeImagePattern, 'src="/wiki/$1"');
|
||||
|
||||
return html;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user