├── nodsoft_moltenobsidian_web ├── vault │ ├── .obsidian │ │ ├── hotkeys.json │ │ ├── community-plugins.json │ │ ├── app.json │ │ ├── appearance.json │ │ ├── core-plugins.json │ │ └── graph.json │ ├── _media │ │ └── icon.png │ ├── .gitignore │ ├── Index.md │ ├── Tool │ │ └── Index.md │ └── Library │ │ └── Vaults Providers │ │ ├── Filesystem.md │ │ └── Index.md ├── src │ ├── env.d.ts │ ├── consts.ts │ ├── styles │ │ ├── _responsive.scss │ │ ├── _variables.scss │ │ ├── _mixins.scss │ │ ├── syntax │ │ │ └── _csharp.scss │ │ └── _content.scss │ ├── components │ │ ├── NavLink.astro │ │ ├── NavLink.astro.scss │ │ ├── vault │ │ │ └── VaultNavTree.astro │ │ ├── BaseHead.astro │ │ └── Sidebar.astro │ ├── layouts │ │ └── Layout.astro │ └── pages │ │ ├── 404.astro │ │ └── [...path].astro ├── public │ ├── icon.png │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── browserconfig.xml │ └── site.webmanifest ├── .vscode │ ├── extensions.json │ └── launch.json ├── tsconfig.json ├── astro.config.mjs ├── .gitignore └── package.json ├── Nodsoft.MoltenObsidian.Tests ├── Assets │ └── TestVault │ │ ├── .obsidian │ │ ├── app.json │ │ ├── appearance.json │ │ ├── core-plugins.json │ │ └── core-plugins-migration.json │ │ ├── VeryNiceFolder │ │ └── Hidden Note.md │ │ └── README.md ├── Vaults │ ├── FileSystem │ │ ├── FileSystemVaultFixtureCollection.cs │ │ └── FileSystemVaultFixture.cs │ └── InMemory │ │ ├── InMemoryVaultFixtureCollection.cs │ │ └── InMemoryVaultFixture.cs └── Nodsoft.MoltenObsidian.Tests.csproj ├── icon.png ├── Nodsoft.MoltenObsidian ├── GlobalUsings.cs ├── version.json ├── Infrastructure │ └── Markdown │ │ ├── Tags │ │ ├── Tag.cs │ │ ├── ObsidianTagsRenderer.cs │ │ └── ObsidianTagsExtension.cs │ │ ├── InternalLinks │ │ └── ObsidianInternalLinksExtension.cs │ │ └── MarkdownExtensions.cs ├── Nodsoft.MoltenObsidian.csproj ├── Vault │ ├── IVaultFolder.cs │ ├── IVaultEntity.cs │ ├── IVaultNote.cs │ ├── IVaultFile.cs │ └── VaultUpdateEventArgs.cs └── Converter │ ├── ObsidianPipelineBuilder.cs │ └── ObsidianHtmlConverter.cs ├── Samples ├── Nodsoft.MoltenObsidian.Samples.HttpWasm │ ├── Layout │ │ └── MainLayout.razor │ ├── Pages │ │ └── Home.razor │ ├── App.razor │ ├── _Imports.razor │ ├── Program.cs │ ├── Nodsoft.MoltenObsidian.Samples.HttpWasm.csproj │ └── wwwroot │ │ └── index.html ├── Nodsoft.MoltenObsidian.Samples.Server │ ├── wwwroot │ │ ├── favicon.ico │ │ └── css │ │ │ └── open-iconic │ │ │ ├── font │ │ │ └── fonts │ │ │ │ ├── open-iconic.eot │ │ │ │ ├── open-iconic.otf │ │ │ │ ├── open-iconic.ttf │ │ │ │ └── open-iconic.woff │ │ │ └── ICON-LICENSE │ ├── Pages │ │ ├── Index.razor │ │ ├── _Host.cshtml │ │ ├── Error.cshtml.cs │ │ ├── _Layout.cshtml │ │ ├── Vault │ │ │ ├── VaultPage.razor │ │ │ └── VaultNoteEditor.razor │ │ └── Error.cshtml │ ├── appsettings.json │ ├── appsettings.Development.json │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── NavMenu.razor │ │ ├── NavMenu.razor.css │ │ └── MainLayout.razor.css │ ├── App.razor │ ├── _Imports.razor │ ├── Nodsoft.MoltenObsidian.Samples.Server.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Program.cs ├── Nodsoft.MoltenObsidian.Samples.Wasm │ ├── wwwroot │ │ ├── favicon.ico │ │ ├── icon-192.png │ │ ├── css │ │ │ └── open-iconic │ │ │ │ ├── font │ │ │ │ └── fonts │ │ │ │ │ ├── open-iconic.eot │ │ │ │ │ ├── open-iconic.otf │ │ │ │ │ ├── open-iconic.ttf │ │ │ │ │ └── open-iconic.woff │ │ │ │ └── ICON-LICENSE │ │ ├── sample-data │ │ │ └── weather.json │ │ └── index.html │ ├── Pages │ │ ├── Index.razor │ │ └── Index.razor.cs │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── SurveyPrompt.razor │ │ ├── NavMenu.razor │ │ ├── NavMenu.razor.css │ │ └── MainLayout.razor.css │ ├── App.razor │ ├── _Imports.razor │ ├── Program.cs │ ├── Nodsoft.MoltenObsidian.Samples.Wasm.csproj │ └── Properties │ │ └── launchSettings.json ├── Nodsoft.MoltenObsidian.Samples.FtpWasm │ ├── wwwroot │ │ ├── favicon.png │ │ ├── icon-192.png │ │ ├── css │ │ │ └── open-iconic │ │ │ │ ├── font │ │ │ │ └── fonts │ │ │ │ │ ├── open-iconic.eot │ │ │ │ │ ├── open-iconic.otf │ │ │ │ │ ├── open-iconic.ttf │ │ │ │ │ └── open-iconic.woff │ │ │ │ └── ICON-LICENSE │ │ ├── sample-data │ │ │ └── weather.json │ │ └── index.html │ ├── Pages │ │ ├── Index.razor │ │ ├── Counter.razor │ │ └── FetchData.razor │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── SurveyPrompt.razor │ │ ├── NavMenu.razor │ │ ├── NavMenu.razor.css │ │ └── MainLayout.razor.css │ ├── _Imports.razor │ ├── Program.cs │ ├── App.razor │ ├── Nodsoft.MoltenObsidian.Samples.FtpWasm.csproj │ └── Properties │ │ └── launchSettings.json ├── Nodsoft.MoltenObsidian.Samples.FtpServer │ ├── wwwroot │ │ ├── favicon.png │ │ └── css │ │ │ └── open-iconic │ │ │ ├── font │ │ │ └── fonts │ │ │ │ ├── open-iconic.eot │ │ │ │ ├── open-iconic.otf │ │ │ │ ├── open-iconic.ttf │ │ │ │ └── open-iconic.woff │ │ │ └── ICON-LICENSE │ ├── Pages │ │ ├── Index.razor │ │ ├── ObsidianText.razor │ │ ├── Counter.razor │ │ ├── Error.cshtml.cs │ │ ├── _Layout.cshtml │ │ ├── FetchData.razor │ │ ├── _Host.cshtml │ │ └── Error.cshtml │ ├── appsettings.json │ ├── appsettings.Development.json │ ├── Data │ │ ├── WeatherForecast.cs │ │ └── WeatherForecastService.cs │ ├── App.razor │ ├── Shared │ │ ├── MainLayout.razor │ │ ├── SurveyPrompt.razor │ │ ├── NavMenu.razor.css │ │ ├── MainLayout.razor.css │ │ └── NavMenu.razor │ ├── _Imports.razor │ ├── Nodsoft.MoltenObsidian.Samples.FtpServer.csproj │ ├── Properties │ │ └── launchSettings.json │ └── Program.cs ├── Nodsoft.MoltenObsidian.Samples.EmbeddedVault │ └── Docs │ │ └── README.md ├── Directory.Build.props └── Nodsoft.MoltenObsidian.Sample.FtpServer │ └── Nodsoft.MoltenObsidian.Samples.FtpServer.csproj ├── Nodsoft.MoltenObsidian.Blazor ├── Templates │ ├── _Imports.razor │ ├── TemplateRenderContextBase.cs │ ├── NotFound.razor │ ├── FoundNote.razor │ ├── Error.razor │ ├── FoundVaultRoot.razor │ ├── FoundFolder.razor │ └── FoundIndexNote.razor ├── _Imports.razor ├── version.json ├── Services │ ├── IVaultRouter.cs │ ├── VaultRouterFactory.cs │ └── VaultRouter.cs ├── Nodsoft.MoltenObsidian.Blazor.csproj ├── ObsidianDependencyInjectionExtensions.cs ├── Helpers │ ├── VaultNavigationHelpers.cs │ └── VaultNavigationRazorHelpers.razor └── ObsidianVaultDisplayOptions.cs ├── Nodsoft.MoltenObsidian.Tool ├── Services │ └── InfoDataPair.cs ├── version.json ├── Program.cs └── Nodsoft.MoltenObsidian.Tool.csproj ├── .config └── dotnet-tools.json ├── Nodsoft.MoltenObsidian.Manifest ├── version.json ├── RemoteVaultManifest.cs ├── ManifestFile.cs ├── Nodsoft.MoltenObsidian.Manifest.csproj ├── moltenobsidian.manifest.schema.json └── VaultManifestGenerator.cs ├── Vaults ├── Nodsoft.MoltenObsidian.Vaults.FileSystem │ ├── version.json │ ├── Data │ │ ├── FileSystemVaultNote.cs │ │ └── FileSystemVaultEntityBase.cs │ ├── Nodsoft.MoltenObsidian.Vaults.FileSystem.csproj │ └── VaultDependencyInjectionExtensions.cs ├── Nodsoft.MoltenObsidian.Vaults.InMemory │ ├── version.json │ ├── Nodsoft.MoltenObsidian.Vaults.InMemory.csproj │ ├── Data │ │ ├── InMemoryVaultNote.cs │ │ └── InMemoryVaultEntityBase.cs │ └── VaultDependencyInjectionExtensions.cs ├── Nodsoft.MoltenObsidian.Vaults.Ftp │ ├── version.json │ ├── Data │ │ ├── FtpRemoteNote.cs │ │ ├── FtpRemoteFolder.cs │ │ └── FtpRemoteFile.cs │ ├── Nodsoft.MoltenObsidian.Vaults.Ftp.csproj │ ├── Utils.cs │ └── VaultDependencyInjectionExtensions.cs ├── Nodsoft.MoltenObsidian.Vaults.Http │ ├── version.json │ ├── Nodsoft.MoltenObsidian.Vaults.Http.csproj │ └── Data │ │ ├── HttpRemoteNote.cs │ │ ├── HttpRemoteFile.cs │ │ └── HttpRemoteFolder.cs ├── Directory.Build.props └── Nodsoft.MoltenObsidian.Vaults.Embedded │ └── EmbeddedVault.cs ├── nodsoft_moltenobsidian_ssg_client ├── package.json ├── pnpm-lock.yaml └── vault-manifest.ts ├── version.json ├── .github └── workflows │ ├── publish-release.yml │ └── build.yml ├── .run ├── Generate docs manifest.run.xml └── Generate site content.run.xml ├── LICENSE ├── Nodsoft.MoltenObsidian.slnx └── Directory.Build.props /nodsoft_moltenobsidian_web/vault/.obsidian/hotkeys.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/.obsidian/app.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/icon.png -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "accentColor": "" 3 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.obsidian/community-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "obsidian-shellcommands" 3 | ] -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | // Global using directives 2 | 3 | global using JetBrains.Annotations; -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/Layout/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | @Body 4 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.obsidian/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "showInlineTitle": false, 3 | "readableLineLength": false 4 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/VeryNiceFolder/Hidden Note.md: -------------------------------------------------------------------------------- 1 | This is a hidden note! 2 | Not at all. 3 | It's just in a folder. -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/icon.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/favicon.ico -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/_media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/vault/_media/icon.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/favicon-16x16.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/favicon-32x32.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/mstile-150x150.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/apple-touch-icon.png -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Templates/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Nodsoft.MoltenObsidian.Vault 2 | @using static Nodsoft.MoltenObsidian.Blazor.Helpers.VaultNavigationRazorHelpers -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/nodsoft_moltenobsidian_web/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.obsidian/appearance.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabledCssSnippets": [ 3 | "site" 4 | ], 5 | "textFontFamily": "Nunito", 6 | "accentColor": "" 7 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tool/Services/InfoDataPair.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Tool.Services; 2 | 3 | public record InfoDataPair(FileInfo FileInfo, byte[] FileData); 4 | 5 | 6 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/favicon.ico -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using Nodsoft.MoltenObsidian.Blazor 2 | @using Nodsoft.MoltenObsidian.Blazor.Helpers.Components 3 | @using Nodsoft.MoltenObsidian.Blazor.Services -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/favicon.png -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/icon-192.png -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/favicon.png -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.EmbeddedVault/Docs/README.md: -------------------------------------------------------------------------------- 1 | # Embedded Vault sample project 2 | This is a sample project that demonstrates how to use the Embedded Vault feature of Molten Obsidian. -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "nbgv": { 6 | "version": "3.5.119", 7 | "commands": [ 8 | "nbgv" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Index 4 | 5 |

Hello, world!

6 | 7 | Welcome to your new app. 8 | 9 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Index 4 | 5 |

Hello, world!

6 | 7 | Welcome to your new app. 8 | 9 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Index 4 | 5 |

Hello, world!

6 | 7 |
8 | 9 | @_convertedMarkdown 10 | 11 | @code { 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.Server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | Index 4 | 5 |

Hello, world!

6 | 7 |
8 | 9 | @_convertedMarkdown 10 | 11 | @code { 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nodsoft/MoltenObsidian/HEAD/Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.gitignore: -------------------------------------------------------------------------------- 1 | .obsidian/* 2 | !.obsidian/app.json 3 | !.obsidian/appearance.json 4 | !.obsidian/config 5 | !.obsidian/community-plugins.json 6 | !.obsidian/core-plugins.json 7 | !.obsidian/graph.json 8 | !.obsidian/hotkeys.json -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Warning" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | This is a test vault, meant to be used with the `Nodsoft.MoltenObsidian.Tests` project's test suite. 4 | 5 | ## See also : 6 | 7 | Check out this #cool_tag and #cooler_tag, and my [[Hidden Note]]. -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props" 7 | ] 8 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict", 3 | "baseUrl": "src", 4 | "esModuleInterop": true, 5 | "resolveJsonModule": true, 6 | "compilerOptions": { 7 | "strictNullChecks": true, 8 | "allowJs": true 9 | } 10 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | ":/Nodsoft.MoltenObsidian/*" 7 | ] 8 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Manifest/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props" 7 | ] 8 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Pages/_Host.cshtml: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @using Nodsoft.MoltenObsidian.Samples.Server 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @{ 5 | Layout = "_Layout"; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/consts.ts: -------------------------------------------------------------------------------- 1 | // Place any global data in this file. 2 | // You can import this data from anywhere in your site by using the `import` keyword. 3 | 4 | export const SITE_TITLE = 'MoltenObsidian'; 5 | // export const SITE_DESCRIPTION = 'Welcome to my website!'; 6 | -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.FileSystem/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props", 7 | ] 8 | } -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.InMemory/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props" 7 | ] 8 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'astro/config'; 2 | import sitemap from "@astrojs/sitemap"; 3 | 4 | // https://astro.build/config 5 | export default defineConfig({ 6 | site: 'https://moltenobsidian.dev', 7 | base: '/', 8 | output: 'static', 9 | integrations: [sitemap()] 10 | }); -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #603cba 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Ftp/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props", 7 | ":/Nodsoft.MoltenObsidian.Manifest/" 8 | ] 9 | } -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Http/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "pathFilters": [ 5 | ".", 6 | "../Directory.Build.props", 7 | ":/Nodsoft.MoltenObsidian.Manifest/" 8 | ] 9 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Pages/ObsidianText.razor: -------------------------------------------------------------------------------- 1 | @page "/vault/{*VaultPath}" 2 | @inject IVault Vault 3 | 4 | @VaultPath 5 | 6 | 7 | 8 | 9 | @code { 10 | [Parameter] public string VaultPath { get; set; } 11 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 4 | "Logging": { 5 | "LogLevel": { 6 | "Default": "Information", 7 | "Microsoft.AspNetCore": "Warning" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tool/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "inherit": true, 4 | "version": "1.0", 5 | "pathFilters": [ 6 | ".", 7 | "../Directory.Build.props", 8 | ":/Nodsoft.MoltenObsidian/*", 9 | ":/Nodsoft.MoltenObsidian.Manifest/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/styles/_responsive.scss: -------------------------------------------------------------------------------- 1 | @use "variables" as *; 2 | 3 | @each $breakpoint, $value in $breakpoints { 4 | .flex-row-#{$breakpoint} { 5 | @media (max-width: $value) { 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | 10 | @media (min-width: $value) { 11 | display: flex; 12 | flex-direction: row; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Data/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Samples.FtpServer.Data; 2 | 3 | public class WeatherForecast 4 | { 5 | public DateOnly Date { get; set; } 6 | 7 | public int TemperatureC { get; set; } 8 | 9 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 10 | 11 | public string? Summary { get; set; } 12 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | 4 | # generated types 5 | .astro/ 6 | 7 | # dependencies 8 | node_modules/ 9 | 10 | # logs 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | # Vault output 24 | public/vault/* -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Templates/TemplateRenderContextBase.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Blazor.Templates; 2 | 3 | /// 4 | /// Defines a base class for all template render context objects. 5 | /// 6 | /// Display options for the current vault display. 7 | public abstract record TemplateRenderContextBase(ObsidianVaultDisplayOptions DisplayOptions); -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
-------------------------------------------------------------------------------- /nodsoft_moltenobsidian_ssg_client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moltenobsidian-ssg-client", 3 | "author": "Nodsoft Systems", 4 | "description": "SSG Client for MoltenObsidian vaults", 5 | "license": "ISC", 6 | "scripts": { 7 | "build": "tsc" 8 | }, 9 | "devDependencies": { 10 | "typescript": "^5.1.6" 11 | }, 12 | "dependencies": { 13 | "@types/mime-types": "^2.1.1", 14 | "yaml": "^2.3.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "file-explorer", 3 | "global-search", 4 | "switcher", 5 | "graph", 6 | "backlink", 7 | "canvas", 8 | "outgoing-link", 9 | "tag-pane", 10 | "page-preview", 11 | "daily-notes", 12 | "templates", 13 | "note-composer", 14 | "command-palette", 15 | "editor-status", 16 | "bookmarks", 17 | "outline", 18 | "word-count", 19 | "file-recovery" 20 | ] -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | 3 | Counter 4 | 5 |

Counter

6 | 7 |

Current count: @currentCount

8 | 9 | 10 | 11 | @code { 12 | private int currentCount = 0; 13 | 14 | private void IncrementCount() 15 | { 16 | currentCount++; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Pages/Counter.razor: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | 3 | Counter 4 | 5 |

Counter

6 | 7 |

Current count: @currentCount

8 | 9 | 10 | 11 | @code { 12 | private int currentCount = 0; 13 | 14 | private void IncrementCount() 15 | { 16 | currentCount++; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.1", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/main", 6 | "^refs/heads/v\\d+(?:\\.\\d+)?$" 7 | ], 8 | "cloudBuild": { 9 | "buildNumber": { 10 | "enabled": true, 11 | "includeCommitId": { 12 | "when": "never" 13 | } 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.obsidian/core-plugins.json: -------------------------------------------------------------------------------- 1 | [ 2 | "file-explorer", 3 | "global-search", 4 | "switcher", 5 | "graph", 6 | "backlink", 7 | "canvas", 8 | "outgoing-link", 9 | "tag-pane", 10 | "page-preview", 11 | "daily-notes", 12 | "templates", 13 | "note-composer", 14 | "command-palette", 15 | "slash-command", 16 | "editor-status", 17 | "bookmarks", 18 | "outline", 19 | "word-count", 20 | "file-recovery" 21 | ] -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Infrastructure/Markdown/Tags/Tag.cs: -------------------------------------------------------------------------------- 1 | using Markdig.Syntax.Inlines; 2 | 3 | namespace Nodsoft.MoltenObsidian.Infrastructure.Markdown.Tags; 4 | 5 | /// 6 | /// Defines an Obsidian Tag within a Markdown document. 7 | /// 8 | /// 9 | public sealed class Tag(string name) : Inline 10 | { 11 | /// 12 | /// The name of the tag. 13 | /// 14 | public string Name { get; } = name; 15 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | // Responsive breakpoints 2 | $breakpoints: ( 3 | xs: 0, 4 | sm: 576px, 5 | md: 768px, 6 | lg: 992px, 7 | xl: 1200px, 8 | xxl: 1400px 9 | ); 10 | 11 | 12 | $accent: #883AEB; 13 | $accent-light: #E0CCFA; 14 | $accent-dark: #310A65; 15 | $accent-gradient: linear-gradient(45deg, $accent, $accent-light 30%, white 60%); 16 | 17 | $background: #13151A; 18 | 19 | $supported-syntaxes: ( 20 | csharp 21 | ); -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.FileSystem/Data/FileSystemVaultNote.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Nodsoft.MoltenObsidian.Vault; 3 | 4 | namespace Nodsoft.MoltenObsidian.Vaults.FileSystem.Data; 5 | 6 | internal sealed class FileSystemVaultNote : FileSystemVaultFile, IVaultNote 7 | { 8 | public FileSystemVaultNote(FileInfo file, IVaultFolder parent, IVault vault) : base(file, parent, vault) { } 9 | 10 | public override string ContentType => "text/markdown"; 11 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 | @Body 15 |
16 |
17 |
-------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Http/Nodsoft.MoltenObsidian.Vaults.Http.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Remote HTTP Vault provider for Molten Obsidian 5 | $(CommonPackageTags), http 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | Nodsoft.MoltenObsidian.Samples.Server 4 | 5 |
6 | 9 | 10 |
11 |
12 | About 13 |
14 | 15 |
16 | @Body 17 |
18 |
19 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Nodsoft.MoltenObsidian.Samples.FtpWasm 10 | @using Nodsoft.MoltenObsidian.Samples.FtpWasm.Shared -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 9 | 10 | @using Microsoft.JSInterop 11 | 12 | @using Nodsoft.MoltenObsidian.Samples.Wasm 13 | @using Nodsoft.MoltenObsidian.Samples.Wasm.Shared -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/Pages/Home.razor: -------------------------------------------------------------------------------- 1 | @page "/{*VaultPath}" 2 | @inject Task VaultTask 3 | 4 | @VaultPath 5 | 6 |

@VaultPath

7 | 8 | @if (VaultTask.IsCompletedSuccessfully) 9 | { 10 | 11 | } 12 | 13 | @code { 14 | [Parameter] public string VaultPath { get; set; } 15 | protected override Task OnInitializedAsync() => VaultTask; 16 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Web; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | using Nodsoft.MoltenObsidian.Samples.Wasm; 4 | 5 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 6 | builder.RootComponents.Add("#app"); 7 | builder.RootComponents.Add("head::after"); 8 | 9 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 10 | 11 | await builder.Build().RunAsync(); -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Services/IVaultRouter.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vault; 2 | 3 | namespace Nodsoft.MoltenObsidian.Blazor.Services; 4 | 5 | /// 6 | /// Specifies a service that routes paths to vault entities. 7 | /// 8 | public interface IVaultRouter 9 | { 10 | /// 11 | /// Routes a path to a vault entity. 12 | /// 13 | /// The path to route. 14 | /// The entity at the specified path. 15 | IVaultEntity? RouteTo(string path); 16 | } -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Ftp/Data/FtpRemoteNote.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Nodsoft.MoltenObsidian.Manifest; 3 | using Nodsoft.MoltenObsidian.Vault; 4 | 5 | namespace Nodsoft.MoltenObsidian.Vaults.Ftp.Data; 6 | 7 | /// 8 | /// Represents a note in a remote FTP vault. 9 | /// 10 | /// 11 | public sealed class FtpRemoteNote : FtpRemoteFile, IVaultNote 12 | { 13 | internal FtpRemoteNote(ManifestFile file, string name, IVaultFolder parent) : base(file, name, parent) { } 14 | } -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Http/Data/HttpRemoteNote.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Nodsoft.MoltenObsidian.Manifest; 3 | using Nodsoft.MoltenObsidian.Vault; 4 | 5 | namespace Nodsoft.MoltenObsidian.Vaults.Http.Data; 6 | 7 | /// 8 | /// Represents a note stored in a remote Molten Obsidian vault, accessible via HTTP. 9 | /// 10 | public sealed class HttpRemoteNote : HttpRemoteFile, IVaultNote 11 | { 12 | internal HttpRemoteNote(ManifestFile file, string name, IVaultFolder parent) : base(file, name, parent) { } 13 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Web; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | using Nodsoft.MoltenObsidian.Samples.FtpWasm; 4 | 5 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 6 | builder.RootComponents.Add("#app"); 7 | builder.RootComponents.Add("head::after"); 8 | 9 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 10 | 11 | 12 | await builder.Build().RunAsync(); -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 | Nodsoft.MoltenObsidian.Samples.FtpServer 4 | 5 |
6 | 9 | 10 |
11 |
12 | About 13 |
14 | 15 |
16 | @Body 17 |
18 |
19 |
-------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Nodsoft.MoltenObsidian.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Base package for Molten Obsidian integrations 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Molten Obsidian", 3 | "short_name": "Molten Obsidian", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/Shared/SurveyPrompt.razor: -------------------------------------------------------------------------------- 1 |
2 | 3 | @Title 4 | 5 | 6 | Please take our 7 | brief survey 8 | 9 | and tell us what you think. 10 |
11 | 12 | @code { 13 | // Demonstrates how a parent component can supply parameters 14 | [Parameter] 15 | public string? Title { get; set; } 16 | 17 | } -------------------------------------------------------------------------------- /Samples/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | 8 | false 9 | 1591 10 | 11 | 12 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2022-01-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2022-01-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2022-01-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2022-01-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2022-01-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2018-05-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing" 6 | }, 7 | { 8 | "date": "2018-05-07", 9 | "temperatureC": 14, 10 | "summary": "Bracing" 11 | }, 12 | { 13 | "date": "2018-05-08", 14 | "temperatureC": -13, 15 | "summary": "Freezing" 16 | }, 17 | { 18 | "date": "2018-05-09", 19 | "temperatureC": -16, 20 | "summary": "Balmy" 21 | }, 22 | { 23 | "date": "2018-05-10", 24 | "temperatureC": -2, 25 | "summary": "Chilly" 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish release 2 | 3 | permissions: 4 | contents: write 5 | 6 | on: 7 | # Push events to matching v*, i.e. v1.0, v20.15.10 8 | push: 9 | tags: 10 | - "v*" 11 | 12 | jobs: 13 | release: 14 | runs-on: ubuntu-latest 15 | 16 | # Actions pinned to commits to prevent supply-chain attacks. 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 20 | 21 | - name: Release 22 | uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1 23 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/vault/.obsidian/graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "collapse-filter": true, 3 | "search": "", 4 | "showTags": false, 5 | "showAttachments": false, 6 | "hideUnresolved": false, 7 | "showOrphans": true, 8 | "collapse-color-groups": true, 9 | "colorGroups": [], 10 | "collapse-display": true, 11 | "showArrow": false, 12 | "textFadeMultiplier": 0, 13 | "nodeSizeMultiplier": 1, 14 | "lineSizeMultiplier": 1, 15 | "collapse-forces": true, 16 | "centerStrength": 0.518713248970312, 17 | "repelStrength": 10, 18 | "linkStrength": 1, 19 | "linkDistance": 250, 20 | "scale": 1, 21 | "close": false 22 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Shared/SurveyPrompt.razor: -------------------------------------------------------------------------------- 1 |
2 | 3 | @Title 4 | 5 | 6 | Please take our 7 | brief survey 8 | 9 | and tell us what you think. 10 |
11 | 12 | @code { 13 | // Demonstrates how a parent component can supply parameters 14 | [Parameter] 15 | public string? Title { get; set; } 16 | 17 | } -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Ftp/Nodsoft.MoltenObsidian.Vaults.Ftp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Remote FTP Vault provider for Molten Obsidian 5 | $(CommonPackageTags), ftp 6 | Spencer Naugler 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.InMemory/Nodsoft.MoltenObsidian.Vaults.InMemory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | In-Memory Vault provider for Molten Obsidian 5 | $(CommonPackageTags), memory 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Shared/SurveyPrompt.razor: -------------------------------------------------------------------------------- 1 |
2 | 3 | @Title 4 | 5 | 6 | Please take our 7 | brief survey 8 | 9 | and tell us what you think. 10 |
11 | 12 | @code { 13 | // Demonstrates how a parent component can supply parameters 14 | [Parameter] 15 | public string? Title { get; set; } 16 | 17 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using Nodsoft.MoltenObsidian.Samples.HttpWasm 10 | @using Nodsoft.MoltenObsidian.Samples.HttpWasm.Layout 11 | @using Nodsoft.MoltenObsidian.Vault 12 | @using Nodsoft.MoltenObsidian.Blazor.Helpers 13 | @using Nodsoft.MoltenObsidian.Blazor -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.InMemory/Data/InMemoryVaultNote.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Nodsoft.MoltenObsidian.Vault; 3 | 4 | namespace Nodsoft.MoltenObsidian.Vaults.InMemory.Data; 5 | 6 | internal sealed class InMemoryVaultNote : InMemoryVaultFile, IVaultNote 7 | { 8 | public InMemoryVaultNote(string name, InMemoryVaultFolder parent, InMemoryVault vault, Stream content) : base(name, parent, vault, content) {} 9 | 10 | public override string ContentType => "text/markdown"; 11 | 12 | public async ValueTask ReadDocumentAsync() => 13 | new(Encoding.UTF8.GetString(await this.ReadBytesAsync()), this); 14 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodsoft_moltenobsidian_web", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "private": true, 6 | "scripts": { 7 | "dev": "astro dev", 8 | "start": "astro dev", 9 | "build": "astro build", 10 | "preview": "astro preview", 11 | "astro": "astro" 12 | }, 13 | "dependencies": { 14 | "@astrojs/sitemap": "^3.1.6", 15 | "astro": "^4.11.0", 16 | "astro-seo-meta": "^4.1.1", 17 | "bootstrap-icons": "^1.11.3", 18 | "moltenobsidian-ssg-client": "link:..\\nodsoft_moltenobsidian_ssg_client", 19 | "sass": "^1.77.6", 20 | "sharp": "^0.33.4" 21 | } 22 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Vaults/FileSystem/FileSystemVaultFixtureCollection.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vaults.FileSystem; 2 | 3 | namespace Nodsoft.MoltenObsidian.Tests.Vaults.FileSystem; 4 | 5 | /// 6 | /// Provides a test fixture for the class. 7 | /// 8 | [CollectionDefinition(nameof(FileSystemVault))] 9 | public abstract class FileSystemVaultFixtureCollection : ICollectionFixture 10 | { 11 | // This class has no code, and is never created. 12 | // Its purpose is simply to be the place to apply [CollectionDefinition] and all the ICollectionFixture<> interfaces. 13 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Authorization 3 | @using Microsoft.AspNetCore.Components.Authorization 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using Nodsoft.MoltenObsidian.Samples.FtpServer 10 | @using Nodsoft.MoltenObsidian.Samples.FtpServer.Shared 11 | @using Nodsoft.MoltenObsidian.Vault 12 | @using Nodsoft.MoltenObsidian.Blazor.Helpers 13 | @using Nodsoft.MoltenObsidian.Blazor; -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.Ftp/Utils.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using FluentFTP; 3 | 4 | namespace Nodsoft.MoltenObsidian.Vaults.Ftp; 5 | 6 | /// 7 | /// Provides utility methods for the FTP vault. 8 | /// 9 | public static class Utils 10 | { 11 | /// 12 | /// Ensures that the client is connected to the server. 13 | /// 14 | public static async ValueTask EnsureConnected(this AsyncFtpClient client) 15 | { 16 | if (!client.IsConnected) 17 | { 18 | await client.Connect(); 19 | } 20 | return client; 21 | } 22 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/components/NavLink.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { HTMLAttributes } from 'astro/types'; 3 | import "./NavLink.astro.scss"; 4 | 5 | type Props = HTMLAttributes<'a'>; 6 | 7 | const { href, class: className, ...props } = Astro.props; 8 | 9 | const { pathname } = Astro.url; 10 | const isIndex = (props as Props)['data-index-note'] === true || className === 'vault-folder-title'; 11 | const normalizedPath = decodeURI(pathname).replace(/^\//, '').replace(isIndex ? /\/(index|readme)$/i : '', ''); 12 | const isActive = href === normalizedPath 13 | 14 | --- 15 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Nodsoft.MoltenObsidian.Samples.FtpServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nodsoft.MoltenObsidian.Samples.FtpServer 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Vaults/InMemory/InMemoryVaultFixtureCollection.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vaults.FileSystem; 2 | using Nodsoft.MoltenObsidian.Vaults.InMemory; 3 | 4 | namespace Nodsoft.MoltenObsidian.Tests.Vaults.InMemory; 5 | 6 | /// 7 | /// Provides a test fixture for the class. 8 | /// 9 | [CollectionDefinition(nameof(InMemoryVault))] 10 | public abstract class InMemoryVaultFixtureCollection : ICollectionFixture 11 | { 12 | // This class has no code, and is never created. 13 | // Its purpose is simply to be the place to apply [CollectionDefinition] and all the ICollectionFixture<> interfaces. 14 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/styles/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin font-styles($size, $weight: 700, $line-height: 1, $margin-bottom: 0.5em) { 2 | font-size: $size; 3 | font-weight: $weight; 4 | line-height: $line-height; 5 | margin-block-end: $margin-bottom; 6 | } 7 | 8 | @mixin bg-acrylic($background) { 9 | background-color: rgba($background, .6); 10 | 11 | -webkit-backdrop-filter: blur(50px); 12 | backdrop-filter: blur(50px); 13 | } 14 | 15 | @mixin code-font() { 16 | font-family: monospace; 17 | font-size: 90%; 18 | } 19 | 20 | @mixin code-block-syntax($langs...) { 21 | @each $lang in $langs { 22 | .lang-#{$lang} .#{$lang} pre { 23 | @content; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Vault/IVaultFolder.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Vault; 2 | 3 | /// 4 | /// Specifies a folder, within an Obsidian vault. 5 | /// 6 | /// 7 | /// This interface is storage-agnostic, and should be able to be implemented using any storage mechanism. 8 | /// 9 | /// 10 | [PublicAPI] 11 | public interface IVaultFolder : IVaultEntity 12 | { 13 | /// 14 | /// The immediate child folders of this folder. 15 | /// 16 | IReadOnlyList Subfolders { get; } 17 | 18 | /// 19 | /// The files inside this folder, excluding subfolders. 20 | /// 21 | IReadOnlyList Files { get; } 22 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | 3 | @using Microsoft.AspNetCore.Authorization 4 | @using Microsoft.AspNetCore.Components.Authorization 5 | @using Microsoft.AspNetCore.Components.Forms 6 | @using Microsoft.AspNetCore.Components.Routing 7 | @using Microsoft.AspNetCore.Components.Web 8 | @using Microsoft.AspNetCore.Components.Web.Virtualization 9 | @using Microsoft.AspNetCore.Mvc.TagHelpers 10 | @using Microsoft.JSInterop 11 | 12 | @using Nodsoft.MoltenObsidian.Blazor 13 | @using Nodsoft.MoltenObsidian.Blazor.Services 14 | 15 | @using Nodsoft.MoltenObsidian.Samples.Server 16 | @using Nodsoft.MoltenObsidian.Samples.Server.Pages 17 | @using Nodsoft.MoltenObsidian.Samples.Server.Shared -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.FileSystem/Nodsoft.MoltenObsidian.Vaults.FileSystem.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Local Filesystem Vault provider for Molten Obsidian 5 | $(CommonPackageTags), filesystem 6 | browser 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Web; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | using Nodsoft.MoltenObsidian.Blazor; 4 | using Nodsoft.MoltenObsidian.Samples.HttpWasm; 5 | 6 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 7 | builder.RootComponents.Add("#app"); 8 | builder.RootComponents.Add("head::after"); 9 | 10 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 11 | 12 | builder.Services.AddMoltenObsidianHttpAsyncVault("https://naratteu.github.io/daangn-garden/"); 13 | builder.Services.AddMoltenObsidianBlazorIntegration(); 14 | 15 | await builder.Build().RunAsync(); -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Manifest/RemoteVaultManifest.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Manifest; 2 | 3 | /// 4 | /// Represents a vault manifest, used to list the contents of a Molten Obsidian vault stored remotely. 5 | /// 6 | public class RemoteVaultManifest 7 | { 8 | /// 9 | /// Default name for a MoltenObsidian vault manifest file. 10 | /// 11 | public const string ManifestFileName = "moltenobsidian.manifest.json"; 12 | 13 | /// 14 | /// The name of the vault. 15 | /// 16 | public string Name { get; init; } = string.Empty; 17 | 18 | /// 19 | /// The relative paths of the files contained in the vault. 20 | /// 21 | public IReadOnlyList Files { get; init; } = []; 22 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Data/WeatherForecastService.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Samples.FtpServer.Data; 2 | 3 | public class WeatherForecastService 4 | { 5 | private static readonly string[] Summaries = new[] 6 | { 7 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 8 | }; 9 | 10 | public Task GetForecastAsync(DateOnly startDate) 11 | { 12 | return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast 13 | { 14 | Date = startDate.AddDays(index), 15 | TemperatureC = Random.Shared.Next(-20, 55), 16 | Summary = Summaries[Random.Shared.Next(Summaries.Length)] 17 | }).ToArray()); 18 | } 19 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | 5 | namespace Nodsoft.MoltenObsidian.Samples.Server.Pages; 6 | 7 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 8 | [IgnoreAntiforgeryToken] 9 | public class ErrorModel : PageModel 10 | { 11 | public string? RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tests/Assets/TestVault/.obsidian/core-plugins-migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "file-explorer": true, 3 | "global-search": true, 4 | "switcher": true, 5 | "graph": true, 6 | "backlink": true, 7 | "canvas": true, 8 | "outgoing-link": true, 9 | "tag-pane": true, 10 | "properties": false, 11 | "page-preview": true, 12 | "daily-notes": true, 13 | "templates": true, 14 | "note-composer": true, 15 | "command-palette": true, 16 | "slash-command": false, 17 | "editor-status": true, 18 | "bookmarks": true, 19 | "markdown-importer": false, 20 | "zk-prefixer": false, 21 | "random-note": false, 22 | "outline": true, 23 | "word-count": true, 24 | "slides": false, 25 | "audio-recorder": false, 26 | "workspaces": false, 27 | "file-recovery": true, 28 | "publish": false, 29 | "sync": false 30 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | 5 | namespace Nodsoft.MoltenObsidian.Samples.FtpServer.Pages; 6 | 7 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 8 | [IgnoreAntiforgeryToken] 9 | public class ErrorModel : PageModel 10 | { 11 | public string? RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Nodsoft.MoltenObsidian.Samples.Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Infrastructure/Markdown/Tags/ObsidianTagsRenderer.cs: -------------------------------------------------------------------------------- 1 | using Markdig.Renderers; 2 | using Markdig.Renderers.Html; 3 | 4 | namespace Nodsoft.MoltenObsidian.Infrastructure.Markdown.Tags; 5 | 6 | /// 7 | /// Provides rendering for Obsidian Tags for Markdig. 8 | /// 9 | public class ObsidianTagsRenderer : HtmlObjectRenderer 10 | { 11 | /// 12 | protected override void Write(HtmlRenderer renderer, Tag obj) 13 | { 14 | if (!renderer.EnableHtmlForInline) 15 | { 16 | return; 17 | } 18 | 19 | renderer.Write(/*lang=html*/$""); 20 | renderer.Write(obj.Name); 21 | renderer.WriteAttributes(obj); 22 | renderer.Write(/*lang=html*/""); 23 | } 24 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.HttpWasm/Nodsoft.MoltenObsidian.Samples.HttpWasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nodsoft.MoltenObsidian.Samples.HttpWasm 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpWasm/Nodsoft.MoltenObsidian.Samples.FtpWasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nodsoft.MoltenObsidian.Samples.FtpWasm 5 | 6 | 7 | 8 | true 9 | 10 | 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Nodsoft.MoltenObsidian.Blazor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Blazor integration for Molten Obsidian 5 | $(CommonPackageTags), blazor 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.FileSystem/Data/FileSystemVaultEntityBase.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vault; 2 | 3 | namespace Nodsoft.MoltenObsidian.Vaults.FileSystem.Data; 4 | 5 | /// 6 | /// Represents a file system vault entity, either a file or a directory. 7 | /// 8 | internal abstract class FileSystemVaultEntityBase : IVaultEntity 9 | { 10 | private protected FileSystemVaultEntityBase(FileSystemInfo entity, IVaultFolder? parent, IVault vault) 11 | { 12 | Name = entity.Name; 13 | Parent = parent; 14 | Path = Parent is null ? "" : System.IO.Path.Combine(Parent.Path, Name).Replace('\\', '/'); 15 | Vault = vault; 16 | } 17 | 18 | public string Name { get; set; } 19 | 20 | public IVaultFolder? Parent { get; } 21 | 22 | // This is the path relative to the vault root. 23 | public string Path { get; } 24 | 25 | public IVault Vault { get; } 26 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Vault/IVaultEntity.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Vault; 2 | 3 | /// 4 | /// Represents a common interface for all vault objects, may they be folders or files. 5 | /// 6 | /// 7 | /// This interface is not intended to be implemented by any class other than the ones provided by the library. 8 | /// 9 | public interface IVaultEntity 10 | { 11 | /// 12 | /// The name of the entity. 13 | /// 14 | string Name { get; } 15 | 16 | /// 17 | /// The full path of the entity, relative to the vault root. 18 | /// 19 | string Path { get; } 20 | 21 | /// 22 | /// The folder that contains this entity. 23 | /// 24 | IVaultFolder? Parent { get; } 25 | 26 | /// 27 | /// The vault that this entity belongs to. 28 | /// 29 | IVault Vault { get; } 30 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:17883", 7 | "sslPort": 44381 8 | } 9 | }, 10 | "profiles": { 11 | "Nodsoft.MoltenObsidian.Samples.Server": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "https://localhost:7016;http://localhost:5242", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "IIS Express": { 21 | "commandName": "IISExpress", 22 | "launchBrowser": true, 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.FtpServer/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:17883", 7 | "sslPort": 44381 8 | } 9 | }, 10 | "profiles": { 11 | "Nodsoft.MoltenObsidian.Samples.FtpServer": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "https://localhost:7016;http://localhost:5242", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "IIS Express": { 21 | "commandName": "IISExpress", 22 | "launchBrowser": true, 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian/Vault/IVaultNote.cs: -------------------------------------------------------------------------------- 1 | namespace Nodsoft.MoltenObsidian.Vault; 2 | 3 | /// 4 | /// Specifies a Markdown file, within an obsidian vault. 5 | /// Once read, this file yields a instance. 6 | /// 7 | /// 8 | /// This interface is storage-agnostic, and should be able to be implemented using any storage mechanism. 9 | /// 10 | /// 11 | /// 12 | [PublicAPI] 13 | public interface IVaultNote : IVaultFile 14 | { 15 | /// 16 | /// The name of the obsidian note. This usually corresponds to the file name, without the extension. 17 | /// 18 | /// 19 | /// This is a convenience property, and is equivalent to without the extension. 20 | /// 21 | string NoteName => Name.EndsWith(".md") ? Name[..^3] : Name; 22 | } -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Samples.Wasm/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Nodsoft.MoltenObsidian.Tests.Wasm 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
Loading...
16 | 17 |
18 | An unhandled error has occurred. 19 | Reload 20 | 🗙 21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Samples/Nodsoft.MoltenObsidian.Sample.FtpServer/Nodsoft.MoltenObsidian.Samples.FtpServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | Nodsoft.MoltenObsidian.Sample.Server 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Templates/NotFound.razor: -------------------------------------------------------------------------------- 1 | @* ReSharper disable once InconsistentNaming *@ 2 | 3 | @code { 4 | /// 5 | /// Default render fragment used when routing doesn't hit any entity. 6 | /// 7 | /// A default render fragment, which simply renders a usual 404 display. 8 | public static RenderFragment Render(NotFoundRenderContext ctx) => __builder => 9 | { 10 |
11 |

No result.

12 |

Nothing was found at path @ctx.Path.

13 |
14 | }; 15 | 16 | /// 17 | /// Render context used when routing doesn't hit any entity. 18 | /// 19 | /// Path that was requested. 20 | /// Display options to use. 21 | public sealed record NotFoundRenderContext(string Path, ObsidianVaultDisplayOptions DisplayOptions) : TemplateRenderContextBase(DisplayOptions); 22 | 23 | } -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Tool/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using Nodsoft.MoltenObsidian.Tool.Commands.Manifest; 4 | using Nodsoft.MoltenObsidian.Tool.Commands.SSG; 5 | using Spectre.Console.Cli; 6 | 7 | CommandApp app = new(); 8 | 9 | app.Configure(static config => 10 | { 11 | config.SetApplicationName("moltenobsidian"); 12 | 13 | #if DEBUG 14 | config.PropagateExceptions(); 15 | config.ValidateExamples(); 16 | #endif 17 | 18 | config.AddBranch("manifest", static manifestConfig => 19 | { 20 | manifestConfig.SetDescription("Manage manifests"); 21 | manifestConfig.AddCommand("generate"); 22 | }); 23 | 24 | config.AddBranch("ssg", static generateConfig => 25 | { 26 | generateConfig.SetDescription("Generate static vault assets"); 27 | generateConfig.AddCommand("generate"); 28 | }); 29 | }); 30 | 31 | return await app.RunAsync(args); -------------------------------------------------------------------------------- /Vaults/Nodsoft.MoltenObsidian.Vaults.InMemory/Data/InMemoryVaultEntityBase.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vault; 2 | 3 | namespace Nodsoft.MoltenObsidian.Vaults.InMemory.Data; 4 | 5 | internal abstract class InMemoryVaultEntityBase : IVaultEntity 6 | { 7 | private protected InMemoryVaultEntityBase(string name, InMemoryVaultFolder? parent, InMemoryVault vault) 8 | { 9 | Name = name; 10 | Parent = parent; 11 | Path = Parent is null ? "" : System.IO.Path.Combine(Parent.Path, Name).Replace('\\', '/'); 12 | Vault = vault; 13 | } 14 | 15 | public string Name { get; } 16 | 17 | public InMemoryVaultFolder? Parent { get; } 18 | 19 | // This is the path relative to the vault root. 20 | public string Path { get; } 21 | 22 | public InMemoryVault Vault { get; } 23 | 24 | 25 | IVault IVaultEntity.Vault => Vault; 26 | IVaultFolder? IVaultEntity.Parent => Parent; 27 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/layouts/Layout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "../styles/_global.scss" 3 | import BaseHead from "../components/BaseHead.astro"; 4 | import Sidebar from "../components/Sidebar.astro"; 5 | import { SITE_TITLE } from "../consts"; 6 | import { ViewTransitions } from "astro:transitions"; 7 | 8 | interface Props { 9 | title: string; 10 | description: string; 11 | } 12 | 13 | const { title, description } = Astro.props; 14 | 15 | const baseHeadTitle = title ? `${title} - ${SITE_TITLE}` : SITE_TITLE; 16 | --- 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 | 36 | 74 | 75 | -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/pages/[...path].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Layout from '../layouts/Layout.astro'; 3 | import { cast, toRelativeVaultPath } from '../vault-utils'; 4 | import { VaultManifestClient } from 'moltenobsidian-ssg-client/manifest-client'; 5 | import type { VaultManifest, VaultFile, VaultFileMetadata } from 'moltenobsidian-ssg-client/vault-manifest'; 6 | import manifest from '../../public/vault/moltenobsidian.manifest.json'; 7 | import fs from 'node:fs/promises'; 8 | import { Seo } from "astro-seo-meta"; 9 | 10 | 11 | export const manifestClient = VaultManifestClient.fromManifest(manifest as VaultManifest); 12 | 13 | 14 | 15 | export async function getStaticPaths() { 16 | const paths = []; 17 | 18 | for (const [path, file] of manifestClient.routingTable) { 19 | const ssgPath = new URL(toRelativeVaultPath(manifestClient.getSsgPath(file)), import.meta.url); 20 | const content = await fs.readFile(ssgPath, 'utf-8'); 21 | const frontMatter = file as VaultFileMetadata ?? {}; 22 | 23 | if (frontMatter.moltenobsidian?.publish === false || frontMatter.obsidian?.publish === false) continue; 24 | 25 | paths.push({ 26 | params: {path: path === '' ? undefined : path}, 27 | props: { 28 | content: content, 29 | ...frontMatter 30 | }, 31 | routing: manifestClient.routingTable 32 | }); 33 | } 34 | 35 | return paths; 36 | } 37 | 38 | const { path } = Astro.params; 39 | const { content, cssclasses } = Astro.props; 40 | --- 41 | 42 | 43 | 59 | 60 |
61 | 62 |
63 |
-------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Blazor/Services/VaultRouter.cs: -------------------------------------------------------------------------------- 1 | using Nodsoft.MoltenObsidian.Vault; 2 | 3 | namespace Nodsoft.MoltenObsidian.Blazor.Services; 4 | 5 | /// 6 | /// Provides Blazor routing for an Obsidian vault. 7 | /// 8 | public sealed class VaultRouter : IVaultRouter 9 | { 10 | private readonly IVault _vault; 11 | private Dictionary _routes; 12 | 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The vault to route. 17 | public VaultRouter(IVault vault) 18 | { 19 | _vault = vault; 20 | _vault.VaultUpdate += OnVaultUpdate; 21 | _routes = BuildRoutingTable(_vault); 22 | } 23 | 24 | private ValueTask OnVaultUpdate(object sender, VaultUpdateEventArgs e) 25 | { 26 | if (e.Type is not UpdateType.Update) 27 | { 28 | // Rebuild the routing table. 29 | _routes = BuildRoutingTable(_vault); 30 | } 31 | 32 | return new(); 33 | } 34 | 35 | /// 36 | /// Routes a path to a vault entity. 37 | /// 38 | /// The path to route. 39 | /// The entity at the specified path. 40 | public IVaultEntity? RouteTo(string path) 41 | { 42 | // Find the route within the routing table. 43 | // First perform a case-sensitive search, falling back to a case-insensitive search if not found. 44 | 45 | if (_routes.TryGetValue(path, out IVaultEntity? caseSensitive)) 46 | { 47 | return caseSensitive; 48 | } 49 | 50 | if (_routes.FirstOrDefault(x => x.Key.Equals(path, StringComparison.OrdinalIgnoreCase)).Value is { } caseInsensitive) 51 | { 52 | return caseInsensitive; 53 | } 54 | 55 | return null; 56 | } 57 | 58 | private static Dictionary BuildRoutingTable(IVault vault) 59 | { 60 | // First. Initialize the routing table. 61 | Dictionary routingTable = []; 62 | 63 | // Folders go first. 64 | foreach (IVaultFolder folder in vault.Folders.Values) 65 | { 66 | routingTable.Add(folder.Path, folder); 67 | } 68 | 69 | // Then markdown files. 70 | foreach (IVaultFile file in vault.Files.Values) 71 | { 72 | // Before adding the file, we clear the extension. 73 | // This is because we want to route to the file without the extension. 74 | // For example, if we have a file named "test.md", we want to route to "/test". 75 | routingTable.Add(file.Path.Replace(".md", ""), file); 76 | } 77 | 78 | return routingTable; 79 | } 80 | } -------------------------------------------------------------------------------- /nodsoft_moltenobsidian_web/src/components/Sidebar.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "./Sidebar.astro.scss" 3 | import NavLink from './NavLink.astro'; 4 | import { Image } from 'astro:assets'; 5 | import logo from '../../public/android-chrome-192x192.png' 6 | import { SITE_TITLE } from '../consts'; 7 | import VaultNavTree from "./vault/VaultNavTree.astro"; 8 | import { buildVaultTree } from "../vault-utils"; 9 | import manifest from '../../public/vault/moltenobsidian.manifest.json'; 10 | import { VaultManifestClient } from "moltenobsidian-ssg-client/manifest-client"; 11 | import { VaultManifest } from "moltenobsidian-ssg-client/vault-manifest"; 12 | 13 | export const manifestClient = VaultManifestClient.fromManifest(manifest as VaultManifest); 14 | 15 | --- 16 | 17 | 52 | 53 | 62 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;net10.0 5 | enable 6 | enable 7 | latest 8 | true 9 | True 10 | latest 11 | true 12 | portable 13 | snupkg 14 | 15 | Nodsoft Systems 16 | Sakura Akeno Isayeki 17 | Molten Obsidian 18 | Molten Obsidian 19 | https://moltenobsidian.dev 20 | https://github.com/Nodsoft/MoltenObsidian 21 | git 22 | obsidian, moltenobsidian, vault, markdown, html, extensions 23 | $(CommonPackageTags) 24 | 25 | README.md 26 | MIT 27 | icon.png 28 | 29 | 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | <_Parameter1>Nodsoft.MoltenObsidian.Tests 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Nodsoft.MoltenObsidian.Manifest/VaultManifestGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using Nodsoft.MoltenObsidian.Vault; 3 | 4 | namespace Nodsoft.MoltenObsidian.Manifest; 5 | 6 | /// 7 | /// Provides manifest generation for a filesystem-based Molten Obsidian vault. 8 | /// 9 | public static class VaultManifestGenerator 10 | { 11 | /// 12 | /// Generates a manifest for the specified vault. 13 | /// 14 | /// The path to the vault. 15 | /// A instance. 16 | public static async Task GenerateManifestAsync(IVault vault) 17 | { 18 | List files = []; 19 | 20 | // Grab all the files in the vault 21 | foreach ((_, IVaultFile file) in vault.Files) 22 | { 23 | if (file.Name is not RemoteVaultManifest.ManifestFileName) 24 | { 25 | files.Add(await ExtractManifestInfoAsync(file)); 26 | } 27 | } 28 | 29 | // Build and return the manifest 30 | return new() 31 | { 32 | Name = vault.Name, 33 | Files = [..files] 34 | }; 35 | } 36 | 37 | /// 38 | /// Extracts manifest information from a vault file. 39 | /// 40 | /// The file to extract information from. 41 | /// A instance. 42 | private static async Task ExtractManifestInfoAsync(IVaultFile file) 43 | { 44 | // Read the file. We'll need it later. 45 | await using Stream stream = await file.OpenReadAsync(); 46 | 47 | // Build a new file object 48 | return new() 49 | { 50 | Path = file.Path, 51 | Hash = await HashDataAsync(stream), 52 | Size = stream.Length, 53 | ContentType = Manifest.MimeTypes.GetMimeType(file.Name), // A fuller namespace is required here because of a conflict with the other apparitions of MimeTypes. 54 | Metadata = file is IVaultNote note ? (await note.ReadDocumentAsync()).Frontmatter : [] 55 | }; 56 | } 57 | 58 | /// 59 | /// Computes the SHA256 hash of the specified stream. 60 | /// 61 | /// The stream to hash. 62 | /// The SHA256 hash of the stream. 63 | internal static async ValueTask HashDataAsync(Stream stream) 64 | { 65 | #if NET7_0_OR_GREATER 66 | return Convert.ToBase64String(await SHA256.HashDataAsync(stream)); 67 | #else 68 | byte[] fileBytes = new byte[stream.Length]; 69 | int readBytesCount = await stream.ReadAsync(fileBytes); 70 | 71 | if (readBytesCount != stream.Length) 72 | { 73 | throw new InvalidOperationException("The file could not be read."); 74 | } 75 | 76 | return Convert.ToBase64String(SHA256.HashData(fileBytes)); 77 | #endif 78 | } 79 | } --------------------------------------------------------------------------------