This repository has been archived by the owner on Oct 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e041f20
commit b886ce1
Showing
5 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<Authors>Kevin Frey, nfdi4plants</Authors> | ||
<Title>Fornax.Nfdi4Plants</Title> | ||
<Description>Loaders, web-component integration and general structures for the Nfdi4Plants documentation</Description> | ||
<!-- <PackageLicenseExpression>MIT</PackageLicenseExpression> --> | ||
<PackageIconUrl>https://raw.githubusercontent.com/nfdi4plants/Branding/138420e3b6f9ec9e125c1ca8840874b2be2a1262/logos/DataPLANT_logo_minimal_rounded_bg_transparent.svg</PackageIconUrl> | ||
<PackageTags></PackageTags> | ||
<RepositoryUrl>https://github.com/Freymaurer/nfdi4plants-fornax-template</RepositoryUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<!-- <FsDocsLicenseLink>https://github.com/nfdi4plants/ISADotNet/blob/developer/LICENSE</FsDocsLicenseLink> | ||
<FsDocsReleaseNotesLink>https://github.com/nfdi4plants/ISADotNet/blob/developer/RELEASE_NOTES.md</FsDocsReleaseNotesLink> --> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net5.0</TargetFramework> | ||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="MarkdigExtensions/nfdi-header.fs" /> | ||
<Compile Include="MarkdigExtensions/nfdi-sidebar-element-header.fs" /> | ||
<Compile Include="Loaders.fs" /> | ||
</ItemGroup> | ||
|
||
|
||
<ItemGroup> | ||
<PackageReference Include="Markdig" Version="0.30.2" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Reference Include="Fornax"> | ||
<HintPath>_lib\Fornax.Core.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
namespace Fornax.Nfdi4Plants | ||
|
||
|
||
module Pipelines = | ||
open Markdig | ||
open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiHeader | ||
open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiSidebarElementHeader | ||
|
||
let markdownPipeline = | ||
MarkdownPipelineBuilder() | ||
.UseAdvancedExtensions() | ||
.UseEmojiAndSmiley() | ||
.UseNFDIHeader() | ||
.Build() | ||
|
||
let sidebarMarkdownPipeline = | ||
MarkdownPipelineBuilder() | ||
.UseSidebarHeader() | ||
.Build() | ||
|
||
[<AutoOpen>] | ||
module Types = | ||
|
||
type DocsConfig = { | ||
disableLiveRefresh: bool | ||
} | ||
|
||
type SidebarElement = { | ||
Title: string | ||
Content: string | ||
} | ||
|
||
type Docs = { | ||
file: string | ||
link : string | ||
title: string | ||
author: string option | ||
published: System.DateTime option | ||
add_toc: bool | ||
sidebar: SidebarElement [] | ||
content: string | ||
} | ||
|
||
module internal Aux = | ||
|
||
let private isSeparator (input : string) = | ||
input.StartsWith "---" | ||
|
||
let private splitKey' (line: string) = | ||
Fornax.Nfdi4Plants.MarkdigExtensions.Aux.splitKey line | ||
|> fun (key, v) -> | ||
v | ||
|> Option.map(fun v -> (key, v)) | ||
|
||
let internal trimString (str : string) = | ||
str.Trim().TrimEnd('"').TrimStart('"') | ||
|
||
// Parse over line to find area between "---". Parse input, very simple by separating by ":" | ||
///`fileConfig` - Metadata at the top of an .md file | ||
let getConfig (fileContent : string) = | ||
let fileContent = fileContent.Split '\n' | ||
let fileContent = fileContent |> Array.skip 1 //First line must be --- | ||
let indexOfSeperator = fileContent |> Array.findIndex isSeparator | ||
fileContent | ||
|> Array.splitAt indexOfSeperator | ||
|> fst | ||
|> Seq.choose splitKey' | ||
|> Map.ofSeq | ||
|
||
open System.IO | ||
open Types | ||
|
||
/// <summary>Read sidebar markdown file at `sidebarPath` to and parse it nfdi-sidebar-element's.</summary> | ||
/// <param name="contentDir">Name of the subfolder in which the docs files are.</param> | ||
/// <param name="sidebarPath">Relative path to sidebar file.</param> | ||
/// <returns>Array of all sidebar elements processed to html and metadata.</returns> | ||
let getSidebar (contentDir: string) (sidebarPath: string)= | ||
let fileContent = | ||
let docsPath = Path.Combine(contentDir, sidebarPath) | ||
File.ReadAllLines(docsPath) | ||
|> Array.skip 1 //First line must be --- | ||
let indexOfSeperator = fileContent |> Array.findIndex isSeparator | ||
let content = | ||
fileContent | ||
|> Array.splitAt indexOfSeperator | ||
|> snd | ||
|> Array.skip 1 // starts with --- | ||
let sidebar = | ||
content | ||
|> List.ofArray | ||
|> List.fold (fun acc line -> | ||
// opens new sidebar element with title | ||
// ` = '\096' | ||
if line.Trim() = "```" then | ||
acc | ||
elif line.StartsWith "```" then | ||
// get sidebar element title | ||
let title = line.Replace("`", "").Trim() | ||
// add to list collection with empty list. | ||
// empty list will be used to add all related lines | ||
(title, List.empty)::acc | ||
elif line.Trim() <> "" then | ||
// match with list collection to check if it is empty (should not be empty, this is error prediction) | ||
match acc with | ||
// if has element, add line to sidebar element | ||
| h::t -> (fst h, line::snd h)::t | ||
// if is empty add sidebar placeholder | ||
| [] -> ("Sidebar", line::[])::acc | ||
else | ||
acc | ||
) [] | ||
|> List.map (fun (title, lines) -> | ||
let c = lines |> List.rev |> String.concat "\n" | ||
{ | ||
Title = title | ||
Content = Markdig.Markdown.ToHtml(c, Pipelines.sidebarMarkdownPipeline) | ||
} | ||
) | ||
|> List.rev | ||
|> Array.ofList | ||
sidebar | ||
|
||
/// <summary>Parse markdown `fileContent` to HTML with markdig and custom nfdi-webcomponent converter.</summary> | ||
/// <param name="fileContent">Markdown file content. Usually whole content of `.md` file.</param> | ||
/// <returns>Returns html as string.</returns> | ||
let getContent (fileContent : string) = | ||
let fileContent = fileContent.Split '\n' | ||
let fileContent = fileContent |> Array.skip 1 //First line must be --- | ||
let indexOfSeperator = fileContent |> Array.findIndex isSeparator | ||
let content = | ||
fileContent | ||
|> Array.splitAt indexOfSeperator | ||
|> snd | ||
|> Array.skip 1 // starts with --- | ||
|> String.concat "\n" | ||
|
||
Markdig.Markdown.ToHtml(content, Pipelines.markdownPipeline) | ||
|
||
[<AutoOpen>] | ||
module Docs = | ||
|
||
open System.IO | ||
open Types | ||
|
||
/// <summary>Parse markdown `fileContent` to HTML with markdig and custom nfdi-webcomponent converter.</summary> | ||
/// <param name="rootDir">Base root directory path, will be appended to 'contentDir'.</param> | ||
/// <param name="contentDir">Folder which to search for docs .md files. This folder will be used a relative root for sidebars.</param> | ||
/// <param name="filePath">Relative path to specific `.md` file.</param> | ||
/// <returns>Returns html as string.</returns> | ||
let loadFile (rootDir: string) (contentDir: string) (filePath: string) = | ||
let text = File.ReadAllText filePath | ||
|
||
let config = Aux.getConfig text | ||
|
||
let title = config |> Map.find "title" |> Aux.trimString | ||
let author = config |> Map.tryFind "author" |> Option.map Aux.trimString | ||
let published = config |> Map.tryFind "published" |> Option.map (Aux.trimString >> System.DateTime.Parse) | ||
let addToc = config |> Map.tryFind "add toc" |> Option.map (Aux.trimString >> System.Boolean.Parse) |> Option.defaultValue true | ||
let addSidebar = | ||
let docsPath = Path.Combine(rootDir, contentDir) | ||
config |> Map.tryFind "add sidebar" |> Option.map (Aux.trimString >> fun x -> Path.Combine(docsPath, x.Replace('\\','/'))) | ||
|
||
let content = Aux.getContent text | ||
let sidebar = addSidebar |> Option.map (Aux.getSidebar contentDir) | ||
let chopLength = | ||
if rootDir.EndsWith(Path.DirectorySeparatorChar) then rootDir.Length | ||
else rootDir.Length + 1 | ||
|
||
let dirPart = | ||
filePath | ||
|> Path.GetDirectoryName | ||
|> fun x -> x.[chopLength .. ] | ||
|
||
let file = Path.Combine(dirPart, (filePath |> Path.GetFileNameWithoutExtension) + ".md").Replace("\\", "/") | ||
let link = "/" + Path.Combine(dirPart, (filePath |> Path.GetFileNameWithoutExtension) + ".html").Replace("\\", "/") | ||
|
||
{ file = file | ||
link = link | ||
title = title | ||
author = author | ||
published = published | ||
content = content | ||
add_toc = addToc | ||
sidebar = if sidebar.IsSome then sidebar.Value else [||] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
namespace Fornax.Nfdi4Plants.MarkdigExtensions | ||
|
||
// https://odetocode.com/blogs/scott/archive/2020/01/23/a-custom-renderer-extension-for-markdig.aspx | ||
// https://github.com/arthurrump/MarkdigExtensions/blob/master/src/MarkdigExtensions.ImageAsFigure/ImageAsFigure.fs | ||
|
||
open Markdig.Renderers | ||
open Markdig | ||
open Markdig.Renderers.Html | ||
open Markdig.Syntax | ||
|
||
module NfdiHeader = | ||
|
||
open System | ||
|
||
type NFDIHeaderRenderer() = | ||
inherit HeadingRenderer() | ||
|
||
override __.Write(renderer : HtmlRenderer, hb : HeadingBlock ) = | ||
|
||
let headingTexts = [| | ||
"nfdi-h1"; | ||
"nfdi-h2"; | ||
"nfdi-h3"; | ||
"nfdi-h4"; | ||
"nfdi-h5"; | ||
"nfdi-h6"; | ||
|] | ||
let index = hb.Level - 1 | ||
let headingText = | ||
if index < headingTexts.Length then | ||
headingTexts[index] | ||
else | ||
// this cannot hit, as any heading with level > 6 will not be rendered as heading, but as <p> | ||
headingTexts.[headingTexts.Length-1] | ||
|
||
if (renderer.EnableHtmlForBlock) then | ||
renderer.Write('<') |> ignore | ||
renderer.Write(headingText) |> ignore | ||
renderer.WriteAttributes(hb) |> ignore | ||
renderer.Write('>') |> ignore | ||
|
||
// renderer.WriteLeafRawLines(hb, true, true, true) |> ignore | ||
renderer.WriteLeafInline(hb) |> ignore | ||
|
||
if (renderer.EnableHtmlForBlock) then | ||
renderer.Write("</") |> ignore | ||
renderer.Write(headingText) |> ignore | ||
renderer.WriteLine(">") |> ignore | ||
|
||
renderer.EnsureLine() |> ignore | ||
|
||
/// | ||
type NFDIHeaderExtension() = | ||
|
||
interface IMarkdownExtension with | ||
|
||
member __.Setup(_) = () | ||
|
||
member __.Setup(_, renderer) = | ||
renderer.ObjectRenderers.ReplaceOrAdd<HeadingRenderer>(new NFDIHeaderRenderer()) |> ignore | ||
|
||
open System.Runtime.CompilerServices | ||
|
||
[<Extension>] | ||
type MarkdownPipelineBuilderExtensions() = | ||
[<Extension>] | ||
// <summary>Highlight code in fenced code blocks</summary> | ||
// <param name="pipeline">The Markdig <see cref="MarkdownPipelineBuilder"/> to add the extension to</param> | ||
static member UseNFDIHeader(pipeline : MarkdownPipelineBuilder) = | ||
pipeline.Extensions.Add(NFDIHeaderExtension()) | ||
pipeline |
84 changes: 84 additions & 0 deletions
84
src/Fornax.Nfdi4Plants/MarkdigExtensions/nfdi-sidebar-element-header.fs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
namespace Fornax.Nfdi4Plants.MarkdigExtensions | ||
|
||
open Markdig.Renderers | ||
open Markdig | ||
open Markdig.Renderers.Html | ||
open Markdig.Syntax | ||
|
||
open System | ||
|
||
module internal Aux = | ||
|
||
let splitKey (line: string) = | ||
let seperatorIndex = line.IndexOf(':') | ||
if seperatorIndex > 0 then | ||
let key = line.[.. seperatorIndex - 1].Trim() | ||
let value = line.[seperatorIndex + 1 ..].Trim() | ||
key, Some value | ||
else | ||
line, None | ||
|
||
module NfdiSidebarElementHeader = | ||
|
||
type SidebarHeaderRenderer() = | ||
inherit HeadingRenderer() | ||
|
||
override __.Write(renderer : HtmlRenderer, hb : HeadingBlock ) = | ||
|
||
let headingTexts = [| | ||
"h1"; | ||
"h2"; | ||
"h3"; | ||
// "nfdi-h4"; | ||
// "nfdi-h5"; | ||
// "nfdi-h6"; | ||
|] | ||
let index = hb.Level - 1 | ||
let headingText = | ||
if index < headingTexts.Length then | ||
headingTexts[index] | ||
else | ||
headingTexts.[headingTexts.Length-1] | ||
let innerText, href = | ||
let s = String.concat "" [for i in hb.Inline do yield i.ToString()] | ||
Aux.splitKey s | ||
|
||
let attr = hb.GetAttributes() | ||
attr.AddProperty("slot", "inner") | ||
if href.IsSome then attr.AddProperty("href", href.Value) | ||
|
||
if (renderer.EnableHtmlForBlock) then | ||
renderer.Write('<') |> ignore | ||
renderer.Write(headingText) |> ignore | ||
renderer.WriteAttributes(hb) |> ignore | ||
renderer.Write('>') |> ignore | ||
|
||
renderer.Write(innerText) |> ignore | ||
|
||
if (renderer.EnableHtmlForBlock) then | ||
renderer.Write("</") |> ignore | ||
renderer.Write(headingText) |> ignore | ||
renderer.WriteLine(">") |> ignore | ||
|
||
renderer.EnsureLine() |> ignore | ||
|
||
/// An extension for Markdig that highlights syntax in fenced code blocks | ||
type SidebarHeaderExtension() = | ||
|
||
interface IMarkdownExtension with | ||
|
||
member __.Setup(_) = () | ||
|
||
member __.Setup(_, renderer) = | ||
renderer.ObjectRenderers.ReplaceOrAdd<HeadingRenderer>(new SidebarHeaderRenderer()) |> ignore | ||
|
||
open System.Runtime.CompilerServices | ||
|
||
[<Extension>] | ||
type MarkdownPipelineBuilderExtensions() = | ||
[<Extension>] | ||
// <summary>Highlight code in fenced code blocks</summary> | ||
// <param name="pipeline">The Markdig <see cref="MarkdownPipelineBuilder"/> to add the extension to</param> | ||
static member UseSidebarHeader(pipeline : MarkdownPipelineBuilder) = | ||
pipeline.Extensions.Add(SidebarHeaderExtension()) | ||
pipeline |
Binary file not shown.