Skip to content

Commit

Permalink
Link to repo in navbar (#1254)
Browse files Browse the repository at this point in the history
  • Loading branch information
mortenpi authored Jul 21, 2022
1 parent 6091d50 commit ef4412f
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 59 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
**For upgrading:** To keep using the Markdown backend, refer to the [DocumenterMarkdown package][documentermarkdown]. That package might not immediately support the latest Documenter version, however.

* ![Enhancement][badge-enhancement] The `ansicolor` keyword to `HTML()` now defaults to true, meaning that executed outputs from `@example`- and `@repl`-blocks are now by default colored (if they emit colored output). ([#1828][github-1828])
* ![Enhancement][badge-enhancement] Documenter now shows a link to the root of the repository in the top navigation bar. The link is determined automatically from the remote repository, unless overridden or disabled via the `repolink` argument of `HTML`. ([#1254][github-1254])
* ![Enhancement][badge-enhancement] A more general API is now available to configure the remote repository URLs via the `repo` argument of `makedocs` by passing objects that are subtypes of `Remotes.Remote` and implement its interface (e.g. `Remotes.GitHub`). ([#1808][github-1808])
* ![Enhancement][badge-enhancement] Broken issue references (i.e. links like `[#1234](@ref)`, but when Documenter is unable to determine the remote GitHub repository) now generate `:cross_references` errors that can be caught via the `strict` keyword. ([#1808][github-1808])

Expand Down Expand Up @@ -903,6 +904,7 @@
[github-1223]: https://github.com/JuliaDocs/Documenter.jl/pull/1223
[github-1232]: https://github.com/JuliaDocs/Documenter.jl/pull/1232
[github-1240]: https://github.com/JuliaDocs/Documenter.jl/pull/1240
[github-1254]: https://github.com/JuliaDocs/Documenter.jl/pull/1254
[github-1258]: https://github.com/JuliaDocs/Documenter.jl/pull/1258
[github-1264]: https://github.com/JuliaDocs/Documenter.jl/pull/1264
[github-1269]: https://github.com/JuliaDocs/Documenter.jl/pull/1269
Expand Down
12 changes: 8 additions & 4 deletions assets/html/scss/documenter/layout/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,16 @@
padding: 0;
margin-left: 0.3em;
}
.docs-settings-button {
margin: auto 0 auto 1rem;
}
.docs-sidebar-button {
font-size: 1.5rem;
margin: auto 0 auto 1rem;
}
.docs-navbar-link {
margin: auto 0.5rem auto 0.5rem;
}
@include touch {
.docs-navbar-link {
margin: auto 0.75rem auto 0.75rem;
}
}
}

Expand Down
10 changes: 6 additions & 4 deletions assets/html/themes/documenter-dark.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions assets/html/themes/documenter-light.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

169 changes: 123 additions & 46 deletions src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import ...Documenter:
Utilities,
Writers

using ...Utilities: Default
using ...Utilities: Default, Remotes
using ...Utilities.JSDependencies: JSDependencies, json_jsescape
import ...Utilities.DOM: DOM, Tag, @tags
using ...Utilities.MDFlatten
Expand Down Expand Up @@ -305,10 +305,15 @@ gather information about the current commit hash and file paths, necessary for c
the links to the remote repository.
**`edit_link`** can be used to specify which branch, tag or commit (when passed a `String`)
in the remote repository the "Edit on ..." links point to. If a special `Symbol` value
`:commit` is passed, the current commit will be used instead. If set to `nothing`, the
link edit link will be hidden altogether. Default value is `"master"`, making the edit link
point to the master branch.
in the remote repository the edit buttons point to. If a special `Symbol` value `:commit`
is passed, the current commit will be used instead. If set to `nothing`, the link edit link
will be hidden altogether. By default, Documenter tries to determine it automatically by
looking at the `origin` remote, and falls back to `"master"` if that fails.
**`repolink`** can be used to override the URL of the Git repository link in the top navbar
(if passed a `String`). By default, Documenter attempts to determine the link from the Git
remote of the repository (e.g. specified via the `remote` argument of
[`makedocs`](@ref Documenter.makedocs)). Passing a `nothing` disables the repository link.
**`canonical`** specifies the canonical URL for your documentation. We recommend
you set this to the base url of your stable documentation, e.g. `https://juliadocs.github.io/Documenter.jl/stable`.
Expand Down Expand Up @@ -402,6 +407,7 @@ struct HTML <: Documenter.Writer
prettyurls :: Bool
disable_git :: Bool
edit_link :: Union{String, Symbol, Nothing}
repolink :: Union{String, Nothing, Default{Nothing}}
canonical :: Union{String, Nothing}
assets :: Vector{HTMLAsset}
analytics :: String
Expand All @@ -420,6 +426,7 @@ struct HTML <: Documenter.Writer
function HTML(;
prettyurls :: Bool = true,
disable_git :: Bool = false,
repolink :: Union{String, Nothing, Default} = Default(nothing),
edit_link :: Union{String, Symbol, Nothing, Default} = Default(Utilities.git_remote_head_branch("HTML(edit_link = ...)", Utilities.currentdir())),
canonical :: Union{String, Nothing} = nothing,
assets :: Vector = String[],
Expand Down Expand Up @@ -469,7 +476,7 @@ struct HTML <: Documenter.Writer
end
end
isa(edit_link, Default) && (edit_link = edit_link[])
new(prettyurls, disable_git, edit_link, canonical, assets, analytics,
new(prettyurls, disable_git, edit_link, repolink, canonical, assets, analytics,
collapselevel, sidebar_sitename, highlights, mathengine, footer,
ansicolor, lang, warn_outdated, prerender, node, highlightjs)
end
Expand Down Expand Up @@ -720,6 +727,17 @@ function render(doc::Documents.Document, settings::HTML=HTML())
@warn "Can't generate landing page (index.html): src/index.md missing" keys(doc.blueprint.pages)
end

if isa(settings.repolink, Default) && (isnothing(doc.user.remote) || Remotes.repourl(doc.user.remote) === nothing)
@warn """
Unable to determine the repository root URL for the navbar link.
This can happen when a string is passed to the `repo` keyword of `makedocs`.
To remove this warning, either pass a Remotes.Remote object to `repo` to completely
specify the remote repository, or explicitly set the remote URL by setting `repolink`
via `makedocs(format = HTML(repolink = "..."), ...)`.
"""
end

ctx = HTMLContext(doc, settings)
ctx.search_index_js = "search_index.js"
ctx.themeswap_js = copy_asset("themeswap.js", doc)
Expand Down Expand Up @@ -1178,66 +1196,125 @@ function render_navbar(ctx, navnode, edit_page_link::Bool)
# The "Edit on GitHub" links and the hamburger to open the sidebar (on mobile) float right
navbar_right = div[".docs-right"]

# Set the logo and name for the "Edit on.." button.
if edit_page_link && (ctx.settings.edit_link !== nothing) && !ctx.settings.disable_git
host_type = Utilities.repo_host_from_url(ctx.doc.user.remote)
if host_type == Utilities.RepoGitlab
host = "GitLab"
logo = "\uf296"
elseif host_type == Utilities.RepoGithub
host = "GitHub"
logo = "\uf09b"
elseif host_type == Utilities.RepoBitbucket
host = "BitBucket"
logo = "\uf171"
elseif host_type == Utilities.RepoAzureDevOps
host = "Azure DevOps"
logo = "\uf3ca" # TODO change to ADO logo when added to FontAwesome
else
host = ""
logo = "\uf15c"
end
hoststring = isempty(host) ? " source" : " on $(host)"

pageurl = get(getpage(ctx, navnode).globals.meta, :EditURL, getpage(ctx, navnode).source)
edit_branch = isa(ctx.settings.edit_link, String) ? ctx.settings.edit_link : nothing
url = if Utilities.isabsurl(pageurl)
pageurl
else
if !(pageurl == getpage(ctx, navnode).source)
# need to set users path relative the page itself
pageurl = joinpath(first(splitdir(getpage(ctx, navnode).source)), pageurl)
end
Utilities.edit_url(ctx.doc.user.remote, pageurl, commit=edit_branch)
# Set up the link to the root of the remote Git repository
#
# By default, we try to determine it from the configured remote. If that fails, the link
# is not displayed. The user can also pass `repolink` to HTML to either disable it
# (repolink = nothing) or override the link URL (if set to a string). In the latter case,
# we try to figure out what icon and string we should use based on the URL.
if !isnothing(ctx.settings.repolink) && (ctx.settings.repolink isa String || ctx.doc.user.remote isa Remotes.Remote)
url, (host, logo) = if ctx.settings.repolink isa String
ctx.settings.repolink, host_logo(ctx.settings.repolink)
else # ctx.doc.user.remote isa Remotes.Remote
Remotes.repourl(ctx.doc.user.remote), host_logo(ctx.doc.user.remote)
end
if url !== nothing
edit_verb = (edit_branch === nothing) ? "View" : "Edit"
title = "$(edit_verb)$hoststring"
# repourl() can sometimes return a nothing (Remotes.URL)
if !isnothing(url)
repo_title = "View the repository" * (isempty(host) ? "" : " on $host")
push!(navbar_right.nodes,
a[".docs-edit-link", :href => url, :title => title](
span[host_type == Utilities.RepoUnknown ? ".docs-icon.fa" : ".docs-icon.fab"](logo),
span[".docs-label.is-hidden-touch"](title)
a[".docs-navbar-link", :href => url, :title => repo_title](
span[".docs-icon.fab"](logo),
span[".docs-label.is-hidden-touch"](isempty(host) ? "Repository" : host)
)
)
end
end
# Add an edit link, with just an icon, but only on pages where edit_page_link is true.
# Some pages, like search, are special and do not have a source file to link to.
edit_page_link && edit_link(ctx, navnode) do logo, title, url
push!(navbar_right.nodes,
a[".docs-navbar-link", :href => url, :title => title](
span[".docs-icon.fas"](logo)
)
)
end

# Settings cog
push!(navbar_right.nodes, a[
"#documenter-settings-button.docs-settings-button.fas.fa-cog",
"#documenter-settings-button.docs-settings-button.docs-navbar-link.fas.fa-cog",
:href => "#", :title => "Settings",
])

# Hamburger on mobile
push!(navbar_right.nodes, a[
"#documenter-sidebar-button.docs-sidebar-button.fa.fa-bars.is-hidden-desktop",
:href => "#"
"#documenter-sidebar-button.docs-sidebar-button.docs-navbar-link.fa.fa-bars.is-hidden-desktop",
:href => "#",
])

# Construct the main <header> node that should be the first element in div.docs-main
header[".docs-navbar"](breadcrumb, navbar_right)
end

"""
Calls `f(logo, title, url)` if it is possible to create an edit link for the `navnode`.
"""
function edit_link(f, ctx, navnode)
view_logo, edit_logo = "\uf15c", "\uf044" # 'file-alt' and 'edit', from .fas class
# Let's fetch the edit path. Usually this is the source file of the page, but the user
# can override it specifying the EditURL option in an @meta block. Usually, it is a
# relative path pointing to a file, but can also be set to an absolute URL.
editpath = get(getpage(ctx, navnode).globals.meta, :EditURL, getpage(ctx, navnode).source)
# If the user has set :EditURL to nothing, then the link will be disabled. Note: the
# .source field of a Page is always a String.
isnothing(editpath) && return
# If the user has set an absolute :EditURL, then we just use that URL without
# modifications. The only thing we want to do is to determine the Git remote host name
# from the URL, if we can. We also use the "view" verb and logo here, since we do not
# know if the remote link allows editing, and so it is the safer option.
if Utilities.isabsurl(editpath)
host, _ = host_logo(editpath)
title = "View source" * (isempty(host) ? "" : " on $(host)")
f(view_logo, title, editpath)
return
end
# If the user has disable Git, then we can not determine edit links
ctx.settings.disable_git && return
# If the user has passed HTML(edit_link = nothing), then all edit links (with relative
# paths) are disabled.
isnothing(ctx.settings.edit_link) && return
# edit_url will call abspath() on the path, but our working directory is set to
# makedocs' root argument. The Page .source paths are already relative to that, but
# user-provided EditURLs are assumed to be relative to the current page. So we need to
# update the path accordingly.
if editpath != getpage(ctx, navnode).source
editpath = joinpath(dirname(getpage(ctx, navnode).source), editpath)
end
# If the user has set `ctx.settings.edit_link = :commit` (only non-String value), then
# we set pass commit=nothing and let edit_url figure out the commit ref with Git.
# We also render a "view" link, instead of the usual "edit" link, since it is usually
# not possible to directly modify the repository files if they refer to a particular
# commit.
verb, logo, commit = if ctx.settings.edit_link === :commit
"View", view_logo, nothing
else
"Edit", edit_logo, ctx.settings.edit_link
end
host, _ = host_logo(ctx.doc.user.remote)
editurl = Utilities.edit_url(ctx.doc.user.remote, editpath, commit=commit)
# It is possible for editurl() to return a nothing, if something goes wrong
isnothing(editurl) && return
# Create the edit link
f(logo, "$verb source" * (isempty(host) ? "" : " on $(host)"), editurl)
return
end

# All these logos are from the .fab (brands) class
const host_logo_github = (host = "GitHub", logo = "\uf09b")
const host_logo_bitbucket = (host = "BitBucket", logo = "\uf171")
const host_logo_gitlab = (host = "GitLab", logo = "\uf296")
const host_logo_azure = (host = "Azure DevOps", logo = "\uf3ca") # microsoft; TODO: change to ADO logo when added to FontAwesome
const host_logo_fallback = (host = "", logo = "\uf841") # git-alt
host_logo(remote::Remotes.GitHub) = host_logo_github
host_logo(remote::Remotes.URL) = host_logo(remote.urltemplate)
host_logo(remote::Union{Remotes.Remote,Nothing}) = host_logo_fallback
function host_logo(remoteurl::String)
occursin("github", remoteurl) ? host_logo_github :
occursin("gitlab", remoteurl) ? host_logo_gitlab :
occursin("bitbucket", remoteurl) ? host_logo_bitbucket :
occursin("azure", remoteurl) ? host_logo_azure :
host_logo_fallback
end

function render_footer(ctx, navnode)
@tags a div nav
# Navigation links (previous/next page), if there are any
Expand Down
2 changes: 1 addition & 1 deletion test/examples/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ examples_html_mathjax2_custom_doc = if "html-mathjax2-custom" in EXAMPLE_BUILDS
),
url = "https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS-MML_HTMLorMML",
),
htmlkwargs = (; edit_link = nothing, repolink = nothing),
)
else
@info "Skipping build: HTML/deploy MathJax v2 (custom URL)"
Expand Down Expand Up @@ -335,7 +336,6 @@ examples_html_local_doc = if "html-local" in EXAMPLE_BUILDS
asset("https://plausible.io/js/plausible.js", class=:js, attributes=Dict(Symbol("data-domain") => "example.com", :defer => ""))
],
prettyurls = false,
edit_branch = nothing,
footer = nothing,
),
)
Expand Down
1 change: 1 addition & 0 deletions test/htmlwriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ end
@test_throws ArgumentError Documenter.HTML(footer="# foo")
@test_throws ArgumentError Documenter.HTML(footer="")
@test Documenter.HTML(footer="foo bar [baz](https://github.com)") isa Documenter.HTML
@test_throws ErrorException Documenter.HTML(edit_branch = nothing, edit_link=nothing)

# MathEngine
let katex = KaTeX()
Expand Down

0 comments on commit ef4412f

Please sign in to comment.