Skip to content
This repository has been archived by the owner on Oct 21, 2024. It is now read-only.

Commit

Permalink
Add lirbary project ✨
Browse files Browse the repository at this point in the history
  • Loading branch information
Freymaurer committed Jun 13, 2022
1 parent e041f20 commit b886ce1
Show file tree
Hide file tree
Showing 5 changed files with 376 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/Fornax.Nfdi4Plants/Fornax.Nfdi4Plants.fsproj
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>
184 changes: 184 additions & 0 deletions src/Fornax.Nfdi4Plants/Loaders.fs
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 [||] }
71 changes: 71 additions & 0 deletions src/Fornax.Nfdi4Plants/MarkdigExtensions/nfdi-header.fs
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
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 added src/Fornax.Nfdi4Plants/_lib/Fornax.Core.dll
Binary file not shown.

0 comments on commit b886ce1

Please sign in to comment.