From 3a35af7aeddf772a1913c8f9439b68755993d278 Mon Sep 17 00:00:00 2001 From: Kevin F Date: Tue, 16 May 2023 21:16:19 +0200 Subject: [PATCH] Add searchbar and new sidebar support #7 #8 --- src/Nfdi4Plants.Fornax/Components.fs | 16 ++-- .../CustomParsing/nfdi-sidebar-element.fs | 56 ++++++++++++ src/Nfdi4Plants.Fornax/Loaders.fs | 90 +++++-------------- .../MarkdigExtensions/Pipelines.fs | 26 ++++++ .../Nfdi4Plants.Fornax.fsproj | 7 +- .../SubComponents/PagefindSearchbar.fs | 22 +++++ 6 files changed, 135 insertions(+), 82 deletions(-) create mode 100644 src/Nfdi4Plants.Fornax/CustomParsing/nfdi-sidebar-element.fs create mode 100644 src/Nfdi4Plants.Fornax/MarkdigExtensions/Pipelines.fs create mode 100644 src/Nfdi4Plants.Fornax/SubComponents/PagefindSearchbar.fs diff --git a/src/Nfdi4Plants.Fornax/Components.fs b/src/Nfdi4Plants.Fornax/Components.fs index 070ab1f..6c24ee1 100644 --- a/src/Nfdi4Plants.Fornax/Components.fs +++ b/src/Nfdi4Plants.Fornax/Components.fs @@ -11,17 +11,11 @@ type Components = class end static member docsLayout (contentGithubUrl:string, docs: Docs) = let publishedDate = docs.published.Value.ToString("yyyy-MM-dd") - let sidebar = [ - if Array.isEmpty docs.sidebar |> not then - for sidebarEle in docs.sidebar do - yield custom "nfdi-sidebar-element" [HtmlProperties.Custom ("slot", "sidebar"); HtmlProperties.Custom ("isActive","true") ] [ - div [HtmlProperties.Custom ("slot", "title")] [!! sidebarEle.Title] - !! sidebarEle.Content - ] - else () - ] - custom "nfdi-body" [Class "content"; if Array.isEmpty docs.sidebar |> not then HtmlProperties.Custom("hasSidebar", "true")] [ - yield! sidebar + let hasSidebar = List.isEmpty docs.sidebar |> not + custom "nfdi-body" [Class "content"; if hasSidebar then HtmlProperties.Custom("hasSidebar", "true")] [ + + if docs.searchbar.IsSome then docs.searchbar.Value + if hasSidebar then yield! docs.sidebar h1 [Class "front-header"] [!! docs.title] i [Class "help" ] [!! $"last updated at {publishedDate}" ] diff --git a/src/Nfdi4Plants.Fornax/CustomParsing/nfdi-sidebar-element.fs b/src/Nfdi4Plants.Fornax/CustomParsing/nfdi-sidebar-element.fs new file mode 100644 index 0000000..bc0ec84 --- /dev/null +++ b/src/Nfdi4Plants.Fornax/CustomParsing/nfdi-sidebar-element.fs @@ -0,0 +1,56 @@ +namespace Fornax.Nfdi4Plants.CustomParsing + +module SidebarElement = + + open Html + open Fornax.Nfdi4Plants.MarkdigExtensions + + type SidebarElement = { + Title: string + Content: string + } + + let read (productionBasePath: string option) (contentArr: string []) = + contentArr + |> 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(productionBasePath)) + } + ) + |> List.rev + |> Array.ofList + + let write (eleArr: SidebarElement []) = + [ + for sidebarEle in eleArr do + yield custom "nfdi-sidebar-element" [HtmlProperties.Custom ("slot", "sidebar"); HtmlProperties.Custom ("isActive","true") ] [ + div [HtmlProperties.Custom ("slot", "title")] [!! sidebarEle.Title] + !! sidebarEle.Content + ] + ] + + diff --git a/src/Nfdi4Plants.Fornax/Loaders.fs b/src/Nfdi4Plants.Fornax/Loaders.fs index 80d2b24..4ca8d9d 100644 --- a/src/Nfdi4Plants.Fornax/Loaders.fs +++ b/src/Nfdi4Plants.Fornax/Loaders.fs @@ -1,35 +1,6 @@ namespace Fornax.Nfdi4Plants open System.IO -module Pipelines = - open Markdig - open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiCode - open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiHeader - open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiSidebarElementHeader - - let markdownPipeline = - MarkdownPipelineBuilder() - .UseAdvancedExtensions() - .UseEmojiAndSmiley() - .UseNFDIHeader() - .UseNFDICodeBlock() - .Build() - - let sidebarMarkdownPipeline(productionBasePath: string option) = - if productionBasePath.IsSome then - MarkdownPipelineBuilder() - .UseSidebarHeader(productionBasePath.Value) - .Build() - else - MarkdownPipelineBuilder() - .UseSidebarHeader() - .Build() - -type SidebarElement = { - Title: string - Content: string -} - type Author = { Name: string // url to profile @@ -52,7 +23,8 @@ type Docs = { add_toc: bool /// Bool if automated "Dataplant Support" block should be added add_support: bool - sidebar: SidebarElement [] + sidebar: HtmlElement list + searchbar: HtmlElement option content: string } @@ -187,14 +159,15 @@ module Aux = add_toc = addToc add_support = addSupport content = "" - sidebar = [||] + sidebar = [] + searchbar = None } /// Read sidebar markdown file at `sidebarPath` to and parse it nfdi-sidebar-element's. /// Name of the subfolder in which the docs files are. /// Relative path to sidebar file. /// Array of all sidebar elements processed to html and metadata. - let getSidebar (contentDir: string) (productionBasePath: string option) (sidebarPath: string) = + let getSidebar (contentDir: string) (productionBasePath: string option) (useOldSidebar:bool) (sidebarPath: string) = let fileContent = let docsPath = Path.Combine(contentDir, sidebarPath) File.ReadAllLines(docsPath) @@ -206,38 +179,12 @@ module Aux = |> 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(productionBasePath)) - } - ) - |> List.rev - |> Array.ofList + if useOldSidebar then + Fornax.Nfdi4Plants.CustomParsing.SidebarElement.read productionBasePath content + |> Fornax.Nfdi4Plants.CustomParsing.SidebarElement.write + else + Fornax.Nfdi4Plants.CustomParsing.SidebarEleneo.read content + |> List.map (Fornax.Nfdi4Plants.CustomParsing.SidebarEleneo.write true) sidebar /// Parse markdown `fileContent` to HTML with markdig and custom nfdi-webcomponent converter. @@ -254,7 +201,7 @@ module Aux = |> Array.skip 1 // starts with --- |> String.concat "\n" - Markdig.Markdown.ToHtml(content, Pipelines.markdownPipeline) + Markdig.Markdown.ToHtml(content, MarkdigExtensions.Pipelines.markdownPipeline) open Aux @@ -266,10 +213,11 @@ type Docs with /// Relative path to specific `.md` file. /// This path can be used if the base path in production is not `/`. This happens in some gh-pages projects. /// Returns html as string. - static member loadFile(rootDir: string, contentDir: string, filePath: string, ?productionBasePath) : Docs = + static member loadFile(rootDir: string, contentDir: string, filePath: string, ?productionBasePath, ?includeSearchbar:bool, ?useOldSidebar: bool) : Docs = try let text = File.ReadAllText filePath - + let includeSearchbar = Option.defaultValue false includeSearchbar + let useOldSidebar = Option.defaultValue false useOldSidebar let config = Aux.getConfig text let docsFromConfig = Docs.createFromConfig config @@ -280,7 +228,10 @@ type Docs with |> Option.map (snd >> Aux.trimString >> fun x -> Path.Combine(docsPath, x.Replace('\\','/'))) let sidebar = - addSidebar |> Option.map (Aux.getSidebar contentDir productionBasePath) + addSidebar |> Option.map (Aux.getSidebar contentDir productionBasePath useOldSidebar) + + let searchbar = + if includeSearchbar then SubComponents.PagefindSearchbar.create(?productionBasePath=productionBasePath) |> Some else None let content = Aux.getContent text @@ -301,7 +252,8 @@ type Docs with file = file link = link content = content - sidebar = if sidebar.IsSome then sidebar.Value else [||] + sidebar = if sidebar.IsSome then sidebar.Value else [] + searchbar = searchbar } with | e -> failwith $"""[Error in file {filePath}] {e.Message}""" diff --git a/src/Nfdi4Plants.Fornax/MarkdigExtensions/Pipelines.fs b/src/Nfdi4Plants.Fornax/MarkdigExtensions/Pipelines.fs new file mode 100644 index 0000000..58d1dc7 --- /dev/null +++ b/src/Nfdi4Plants.Fornax/MarkdigExtensions/Pipelines.fs @@ -0,0 +1,26 @@ +namespace Fornax.Nfdi4Plants.MarkdigExtensions + +module Pipelines = + + open Markdig + open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiCode + open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiHeader + open Fornax.Nfdi4Plants.MarkdigExtensions.NfdiSidebarElementHeader + + let markdownPipeline = + MarkdownPipelineBuilder() + .UseAdvancedExtensions() + .UseEmojiAndSmiley() + .UseNFDIHeader() + .UseNFDICodeBlock() + .Build() + + let sidebarMarkdownPipeline(productionBasePath: string option) = + if productionBasePath.IsSome then + MarkdownPipelineBuilder() + .UseSidebarHeader(productionBasePath.Value) + .Build() + else + MarkdownPipelineBuilder() + .UseSidebarHeader() + .Build() \ No newline at end of file diff --git a/src/Nfdi4Plants.Fornax/Nfdi4Plants.Fornax.fsproj b/src/Nfdi4Plants.Fornax/Nfdi4Plants.Fornax.fsproj index 4420c01..d18ea5b 100644 --- a/src/Nfdi4Plants.Fornax/Nfdi4Plants.Fornax.fsproj +++ b/src/Nfdi4Plants.Fornax/Nfdi4Plants.Fornax.fsproj @@ -18,15 +18,18 @@ true - + + + + - + diff --git a/src/Nfdi4Plants.Fornax/SubComponents/PagefindSearchbar.fs b/src/Nfdi4Plants.Fornax/SubComponents/PagefindSearchbar.fs new file mode 100644 index 0000000..152acf9 --- /dev/null +++ b/src/Nfdi4Plants.Fornax/SubComponents/PagefindSearchbar.fs @@ -0,0 +1,22 @@ +namespace Fornax.Nfdi4Plants.SubComponents + +open Html + +type PagefindSearchbar = class end + with + static member create (?productionBasePath: string) = + let appendBasePath (url: string) = + let p = Option.defaultValue "" productionBasePath + p.TrimEnd([|'/'; '\\'|]) + url + div [HtmlProperties.Custom("slot","searchbar")] [ + link [Href <| appendBasePath "/_pagefind/pagefind-ui.css"; Rel "stylesheet"] + script [Src <| appendBasePath "/_pagefind/pagefind-ui.js"; Type "text/javascript"] [] + div [Id "search"] [] + script [] [ + !!"""window.addEventListener('DOMContentLoaded', (event) => { + new PagefindUI({ element: "#search" }); +});""" + ] + ] + +