Skip to content

Commit

Permalink
Merge pull request #758 from alanlomeli/customize-menu-items
Browse files Browse the repository at this point in the history
Proposal for custom templating
  • Loading branch information
dsyme authored Aug 16, 2022
2 parents a4a5c93 + 8b462ad commit d981c2e
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ version.props
src/Common/AssemblyInfo.?s
tests/FSharp.Literate.Tests/output1/
.vscode/
.DS_Store
21 changes: 21 additions & 0 deletions docs/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,27 @@ with the existing default template.
> NOTE: There is no guarantee that your template will continue to work with future versions of F# Formatting.
> If you do develop a good template please consider contributing it back to F# Formatting.
## Customizing menu items by template

You can add advanced styling to the sidebar generated menu items by creating a new template for it.
`fsdoc` will look for menu templates in the `--input` folder which defaults to the docs folder.

To customize the generated menu-item headers, use file `_menu_template.html` with starting template:

```html
<li class="nav-header">
{{fsdocs-menu-header-content}}
</li>
{{fsdocs-menu-items}}
```

Similarly, to customize the individual menu item list, use file `_menu-item_template.html` with starting template:

```html
<li class="nav-item"><a href="{{fsdocs-menu-item-link}}" class="nav-link">{{fsdocs-menu-item-content}}</a></li>
```
Do note that files need to be added prior running or won't be generated.
In case you want to get a unique identifier for a header or menu item, you can use `{{fsdocs-menu-header-id}}` and `{{fsdocs-menu-item-id}}`, respectively.

## Customizing by generating your own site using your own code

Expand Down
10 changes: 6 additions & 4 deletions src/FSharp.Formatting.ApiDocs/ApiDocs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ type ApiDocs =
?libDirs,
?otherFlags,
?urlRangeHighlight,
?onError
?onError,
?menuTemplateFolder
) =
let root = defaultArg root "/"
let qualify = defaultArg qualify false
Expand All @@ -106,7 +107,7 @@ type ApiDocs =
extensions = extensions
)

let renderer = GenerateHtml.HtmlRender(model)
let renderer = GenerateHtml.HtmlRender(model, ?menuTemplateFolder = menuTemplateFolder)

let index = GenerateSearchIndex.searchIndexEntriesForModel model

Expand Down Expand Up @@ -184,7 +185,8 @@ type ApiDocs =
?libDirs,
?otherFlags,
?urlRangeHighlight,
?onError
?onError,
?menuTemplateFolder
) =
let root = defaultArg root "/"
let qualify = defaultArg qualify false
Expand All @@ -205,7 +207,7 @@ type ApiDocs =
extensions = extensions
)

let renderer = GenerateMarkdown.MarkdownRender(model)
let renderer = GenerateMarkdown.MarkdownRender(model, ?menuTemplateFolder = menuTemplateFolder)

let index = GenerateSearchIndex.searchIndexEntriesForModel model

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<Compile Include="GenerateMarkdown.fs" />
<Compile Include="GenerateSearchIndex.fs" />
<Compile Include="ApiDocs.fs" />
<InternalsVisibleTo Include="FSharp.ApiDocs.Tests" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FSharp.Formatting.Common\FSharp.Formatting.Common.fsproj" />
Expand Down
41 changes: 37 additions & 4 deletions src/FSharp.Formatting.ApiDocs/GenerateHtml.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ open FSharp.Formatting.HtmlModel.Html
/// Embed some HTML generateed in GenerateModel
let embed (x: ApiDocHtml) = !!x.HtmlText

type HtmlRender(model: ApiDocModel) =
type HtmlRender(model: ApiDocModel, ?menuTemplateFolder: string) =
let root = model.Root
let collectionName = model.Collection.CollectionName
let qualify = model.Qualify
Expand Down Expand Up @@ -615,9 +615,42 @@ type HtmlRender(model: ApiDocModel) =
| _ -> () ]

let listOfNamespacesNav otherDocs (nsOpt: ApiDocNamespace option) =
listOfNamespacesNavAux otherDocs nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"
let isTemplatingAvailable =
match menuTemplateFolder with
| None -> false
| Some input -> Menu.isTemplatingAvailable input

if isTemplatingAvailable then
if otherDocs && model.Collection.CollectionName <> "FSharp.Core" then
let menuItems =
let title = "All Namespaces"
let link = model.IndexFileUrl(root, collectionName, qualify, model.FileExtensions.InUrl)

[ { Menu.MenuItem.Link = link
Menu.MenuItem.Content = title } ]

Menu.createMenu menuTemplateFolder.Value "API Reference" menuItems

else
let categorise = Categorise.model model

if categorise.Length = 0 then
""
else
let menuItems =
categorise
|> List.map (fun (_, ns) ->
let link = ns.Url(root, collectionName, qualify, model.FileExtensions.InUrl)
let name = ns.Name

{ Menu.MenuItem.Link = link
Menu.MenuItem.Content = name })

Menu.createMenu menuTemplateFolder.Value "Namespaces" menuItems
else
listOfNamespacesNavAux otherDocs nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"

/// Get the substitutions relevant to all
member _.GlobalSubstitutions: Substitutions =
Expand Down
42 changes: 38 additions & 4 deletions src/FSharp.Formatting.ApiDocs/GenerateMarkdown.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module internal FSharp.Formatting.ApiDocs.GenerateMarkdown
open System
open System.IO
open System.Web
open FSharp.Formatting.Common
open FSharp.Formatting.Markdown
open FSharp.Formatting.Markdown.Dsl
open FSharp.Formatting.Templating
Expand All @@ -22,7 +23,7 @@ let embed (x: ApiDocHtml) = !!(htmlString x)
let embedSafe (x: ApiDocHtml) = !!(htmlStringSafe x)
let br = !! "<br />"

type MarkdownRender(model: ApiDocModel) =
type MarkdownRender(model: ApiDocModel, ?menuTemplateFolder: string) =
let root = model.Root
let collectionName = model.Collection.CollectionName
let qualify = model.Qualify
Expand Down Expand Up @@ -362,9 +363,42 @@ type MarkdownRender(model: ApiDocModel) =
| _ -> () ]

let listOfNamespaces otherDocs nav (nsOpt: ApiDocNamespace option) =
listOfNamespacesAux otherDocs nav nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"
let isTemplatingAvailable =
match menuTemplateFolder with
| None -> false
| Some input -> Menu.isTemplatingAvailable input

if isTemplatingAvailable then
if otherDocs && nav && model.Collection.CollectionName <> "FSharp.Core" then
let menuItems =
let title = "All Namespaces"
let link = model.IndexFileUrl(root, collectionName, qualify, model.FileExtensions.InUrl)

[ { Menu.MenuItem.Link = link
Menu.MenuItem.Content = title } ]

Menu.createMenu menuTemplateFolder.Value "API Reference" menuItems

else
let categorise = Categorise.model model

if categorise.Length = 0 then
""
else
let menuItems =
categorise
|> List.map (fun (_, ns) ->
let link = ns.Url(root, collectionName, qualify, model.FileExtensions.InUrl)
let name = ns.Name

{ Menu.MenuItem.Link = link
Menu.MenuItem.Content = name })

Menu.createMenu menuTemplateFolder.Value "Namespaces" menuItems
else
listOfNamespacesAux otherDocs nav nsOpt
|> List.map (fun html -> html.ToString())
|> String.concat " \n"

/// Get the substitutions relevant to all
member _.GlobalSubstitutions: Substitutions =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<Compile Include="PynbModel.fs" />
<Compile Include="HtmlModel.fs" />
<Compile Include="Templating.fs" />
<Compile Include="Menu.fs" />
</ItemGroup>
<Import Project="..\..\.paket\Paket.Restore.targets" />
</Project>
55 changes: 55 additions & 0 deletions src/FSharp.Formatting.Common/Menu.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module FSharp.Formatting.Common.Menu

open System
open System.IO
open FSharp.Formatting.Templating

type MenuItem = { Link: string; Content: string }

let private snakeCase (v: string) =
System
.Text
.RegularExpressions
.Regex
.Replace(v, "[A-Z]", "$0")
.Replace(" ", "_")
.ToLower()

let createMenu (input: string) (header: string) (items: MenuItem list) : string =
let pwd = Directory.GetCurrentDirectory()
let menuTemplate = File.ReadAllText(Path.Combine(pwd, input, "_menu_template.html"))
let menuItemTemplate = File.ReadAllText(Path.Combine(pwd, input, "_menu-item_template.html"))

let menuItems =
items
|> List.map (fun (model: MenuItem) ->
let link = model.Link
let title = System.Web.HttpUtility.HtmlEncode model.Content
let id = snakeCase title

SimpleTemplating.ApplySubstitutionsInText
[| ParamKeys.``fsdocs-menu-item-link``, link
ParamKeys.``fsdocs-menu-item-content``, title
ParamKeys.``fsdocs-menu-item-id``, id |]
menuItemTemplate)
|> String.concat "\n"

SimpleTemplating.ApplySubstitutionsInText
[| ParamKeys.``fsdocs-menu-header-content``, header
ParamKeys.``fsdocs-menu-header-id``, snakeCase header
ParamKeys.``fsdocs-menu-items``, menuItems |]
menuTemplate

let isTemplatingAvailable (input: string) : bool =
let pwd = Directory.GetCurrentDirectory()
let menuTemplate = Path.Combine(pwd, input, "_menu_template.html")
let menuItemTemplate = Path.Combine(pwd, input, "_menu-item_template.html")
File.Exists(menuTemplate) && File.Exists(menuItemTemplate)

let getLastWriteTimes (input: string) : DateTime list =
let pwd = Directory.GetCurrentDirectory()

let getLastWriteTime f =
Path.Combine(pwd, input, f) |> File.GetLastWriteTime

[ getLastWriteTime "_menu_template.html"; getLastWriteTime "_menu-item_template.html" ]
18 changes: 18 additions & 0 deletions src/FSharp.Formatting.Common/Templating.fs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,24 @@ module ParamKeys =
/// A parameter key known to FSharp.Formatting
let ``fsdocs-watch-script`` = ParamKey "fsdocs-watch-script"

/// A parameter key known to FSharp.Formatting, available in _menu_template.html
let ``fsdocs-menu-header-content`` = ParamKey "fsdocs-menu-header-content"

/// A parameter key known to FSharp.Formatting, available in _menu_template.html
let ``fsdocs-menu-header-id`` = ParamKey "fsdocs-menu-header-id"

/// A parameter key known to FSharp.Formatting, available in _menu_template.html
let ``fsdocs-menu-items`` = ParamKey "fsdocs-menu-items"

/// A parameter key known to FSharp.Formatting, available in _menu-item_template.html
let ``fsdocs-menu-item-link`` = ParamKey "fsdocs-menu-item-link"

/// A parameter key known to FSharp.Formatting, available in _menu-item_template.html
let ``fsdocs-menu-item-content`` = ParamKey "fsdocs-menu-item-content"

/// A parameter key known to FSharp.Formatting, available in _menu-item_template.html
let ``fsdocs-menu-item-id`` = ParamKey "fsdocs-menu-item-id"

module internal SimpleTemplating =

#if NETSTANDARD2_0
Expand Down
Loading

0 comments on commit d981c2e

Please sign in to comment.