Closed Andre601 closed 3 years ago
Unfortunately, we can't do anything about that, as navigation is core-MkDocs and not compatible with our icon integration. The same goes for the table of contents.
Good to know... I assume making a plugin for this could maybe fix it? Otherwise, will I probably open an issue on MkDocs to request the options that either extensions or plugins should be able to alter those things.
You can use literal emoji code points, but not the :...:
syntax. I don't know if it's possible to hook into the nav generation, maybe @facelessuser has an idea?
https://python-markdown.github.io/extensions/toc/#custom-labels
This seems to only apply to the ToC, no?
This seems to only apply to the ToC, no?
Yes, this applies to TOC navigation, but not document page navigation.
Upstream response was that it's not something that belongs in upstream, but something a theme is perfectly capable of supporting: https://github.com/mkdocs/mkdocs/issues/2311#issuecomment-785386132
An alternative approach that might work is CSS, but that's a bit detached from the nav label and a bit more difficult to manage/target nav items (eg when nav is modified could break it if relying on list order for targeting).
A project I'm migrating docs for has had a request for external links to indicate that they're external (and I guess they should additionally have attribute to open a new tab instead of navigate away from docs). They also want to use the FA external link icon for this purpose.
For external links at least, it's probably easier to implement, by detecting a third-party link in the nav? Then just adding a class might be sufficient and CSS can assign the external link icon to each. Probably want to additionally modify the HTML though to add that attribute for opening a new tab.
We can't do anything about it in Material for MkDocs, as we're only rendering what's there. IMHO, things would have to be solved in a plugin (for navigation) or extension (for table of contents).
We can't do anything about it in Material for MkDocs, as we're only rendering what's there.
I thought you're using JS to manipulate client-side and possibly some additions (or included third-party plugins/extensions) that do modifications at build?
Seems like something that could be handled via JS without an issue, but I understand why you may be reluctant to pursue that, especially if demand for it is low from the community/insiders.
We're using JavaScript only to enhance the application and where it's absolutely necessary. If you disable JavaScript, you will see that basically, 80% of the theme will look the same. Features as search and instant loading that are interactive won't work obviously. This is one of the core values of Material for MkDocs - it should even work on slow Internet connections (i.e. emerging markets). Handling this via JS would mean that we would need to load the complete icon and emoji index which currently weights 577k - that's 5 times the whole JavaScript + CSS payload. Furthermore, this would need to block rendering, or we would introduce content shift. Therefore it's barely a solution. Unfortunately, this really needs to be solved upstream.
This is one of the core values of Material for MkDocs - it should even work on slow Internet connections (i.e. emerging markets).
I'm not familiar with the build pipeline. In JS web dev land, it's not uncommon for SSGs to have a build step that uses JS to build/pre-render page content that on the frontend client becomes interactive with JS if available. Gatsby has established a reputation for doing that fairly well, along with Next.js, both React based.
I assume python is used for the build step, and that it would be possible to add some logic here, but if that's out of the scope of mkdocs-material
that's fine.
As for those with JS disabled, it's a nice-to-have but that wouldn't be reason enough to completely dismiss such a feature.
For slower connections there are solutions for that too, but perhaps I'm too used to modern web dev and you're limited to what you can do here with MkDocs. A single glyph shouldn't be a major concern however.
Handling this via JS would mean that we would need to load the complete icon and emoji index which currently weights 577k - that's 5 times the whole JavaScript + CSS payload.
Apart from a build step filtering this to be a non-issue, there are other ways around that.
However, the interest for just treating external links with a different behaviour (open new tab instead of change the existing page) and include a glyph to make these items distinct from relative/internal links seems like a fair and common feature.
Furthermore, this would need to block rendering, or we would introduce content shift. Therefore it's barely a solution. Unfortunately, this really needs to be solved upstream.
I don't see why that'd be the case tbh. Depends on how you approach it.
For external links at least, it's probably easier to implement, by detecting a third-party link in the nav?
This should be rather simple to do as external links are different Python objects (mkdocs.structure.nav.Link) than internal links (mkdocs.structure.pages.Page). A simple if
statement in the template should be able to provide different output much like is already done for nav sections. All three types of objects include the same three attributes: is_section
, is_page
and is_link
, only one of which is ever True
. See the documentation.
Made a basic implementation:
Originally I tried inlining the SVG via background-image
, but this prevented being able to modify/inherit the colour.
// SVG via CSS var defined wherever would be relevant:
// --md-nav-icon--external: svg-load("octicons/link-external-16.svg");
// _tabs.scss: `&__link{}`
&-external::after {
content: "";
/* sets an position/scale followed by SVG */
background: center/70% no-repeat var(--md-nav-icon--external);
/* Required for visibility */
padding-left: 1rem;
}
I considered the mask-image
approach that's been used already by @squidfunk but I know how he feels about maintenance and complicating things. There seems to be some non-DRY usage of that mask-image
technique, which could probably be refactored to leverage SCSS features, but I opted out of exploring this route.
Instead I figured the usual approach with font icon glyphs instead of SVGs might be more appropriate. I realize @squidfunk is probably opposed to including complete fonts wastefully, so I just extracted the external link glyph into it's own web font (woff) file.
This could bundle multiple glyphs if appropriate (might be useful for heading permalink icon?), here's basic CSS for re-creating the solution:
// _icons.scss
// Just place the font in the `material` theme location, could use a CSS var or a user could override the file if they want to use different glyph(s)
@font-face {
font-family: 'external-link';
src: url('/assets/fonts/external-link.woff') format('woff');
}
// Avoids repeating the style or requiring sibling class by matching any class with the prefix:
[class*='md-glyph--']:before {
display: inline-block;
font-family: 'external-link';
/* At least for this glyph, it's too big by default, may be better suited below or handled when generating the font */
font-size: 80%;
}
.md-glyph {
// If more icons were bundled, just add the glyph modifier and set `content` to it's mapping (eg "A" or "\0041")
&--external-link:before { content:'\0041'; }
}
Then the Jinja templates with the info @waylan provided:
<!-- tabs-item.html#L52 -->
<a href="{{ nav_item.url | url }}" class="{{ class }} {{ 'md-glyph--external-link' if nav_item.is_link }}">
<!-- nav-item.html#131 -->
<a href="{{ nav_item.url | url }}" class="md-nav__link {{ 'md-glyph--external-link' if nav_item.is_link }}">
As I'm not familiar with the code base, it's possible I've missed something there. The woff is 1KB in weight, I did no effort to optimize that and used an online web generator instead of putting something proper together with NodeJS or similar.
You could add to your build a way to either extract font glyphs or build a font from SVG inputs, or just include the pre-built font like I have and if anyone wants to change that, they just swap the file or change the path to their own font.
I can PR these changes if you're interested. I don't have time to contribute anything more extensive (like refactoring your SCSS or adding a font generator to your build pipeline.
One other option, is just adding a class only and expecting all users that want this to provide the additional CSS and font file themselves. This would be inconvenient, but probably the most acceptable option for @squidfunk if he's opposed to any solution mentioned in my prior comment.
With the font loaded, then CSS can be used to target external links like this:
EDIT: Just noticed the MkDocs nav URLs are relative href
values, so third-party CSS can probably make do with this slightly more verbose approach without a class to target:
/* my-third-party.css */
/* tab or nav sidebar with non-relative links will pre-pend an icon from the given font-family */
.md-tabs__link[href^="http"]::before, .md-nav__link[href^="http"]::before {
display: inline-block;
font-family: 'external-link';
font-size: 80%;
content: '\0041';
}
Your last EDIT is the way to go 👍 no additional code necessary. We shouldn’t re-introduce web fonts, as the SVG approach is superior.
Your last EDIT is the way to go 👍 no additional code necessary. We shouldn’t re-introduce web fonts, as the SVG approach is superior.
Not quite sure how the last one even is different? Like from the looks of it would you still need to add a own font-family for it? Like I have a somewhat hard time to understand this entire thing now, so if someone could give me a dumbed-down version of this (Where the icon would also be after the text) would I be happy about it...
Yes, I meant there is nothing we need to add (additional CSS classes) to the theme to make this (add an icon to external links) work. You still need to bring your own webfont or SVG via mask-image, thus customize it.Custom Admonitions give a start how the mask-image approach can be pulled off 😊
Like from the looks of it would you still need to add a own font-family for it?
Yes, you must provide your own font file and font-family CSS similar to what the earlier post had. Most font generators will produce this for you, but their icon CSS is class based like the earlier example, so you need to add a class to use them.
You can pull in all of an existing font like FontAwesome, but it will be weighty vs a single glyph font like I created. Honestly it's lightweight that it's something I think this theme should be open to including, with a simple toggle to enable, but I'm familiar enough with how this project is maintained to know what the outcome was likely to be.
Users that want this will have to be familiar with provisioning a custom font, or the wasteful usage of a full icon font, in addition to adding the custom CSS.
if someone could give me a dumbed-down version of this (Where the icon would also be after the text) would I be happy about it...
The icon is prepended to the nav or tab item text, just like the screenshots show.
You could change this to append instead, switch the ::before
to ::after
in the CSS. I added comments in the CSS snippets to help explain what was going on a bit better for users less comfortable with CSS (or this approach in general).
It will offset your text as if the font icon was included in the text itself, so you shouldn't have any layout issues occur.
~I have not tested it against other features like Instant Navigation from this theme. That is known to rewrite URLs, but I only investigated it's impact on <script>
elements. @squidfunk can confirm if it will also rewrite the href
of the nav <a>
elements too.~ (EDIT: Instant Nav should be fine, href
seems to remain relative)
<details>
comment "Generic Selector" and modify that to target or exclude href
values. Obviously not pleasant but you don't have much choice beyond this to workaround it.[...] that's been used already by @squidfunk but I know how he feels about maintenance and complicating things.
[...] but I'm familiar enough with how this project is maintained to know what the outcome was likely to be.
This is a problem that happens when @squidfunk won't even consider @waylan advice on how to detect page links from external links (just a Jinja template condition in two places to add a class that can be targeted).
I must kindly remind you again to adhere to the code of conduct. This is your second warning (first one was here).
I haven't read a compelling reason why we need that template switch. It's perfectly achievable with a few lines of CSS. In fact, the CSS-only solution is superior, because some authors also want to add external link symbols to the body copy which is generated from Markdown, and we can't add/inject switches there. Authors would be required to add the respective CSS class via attribute list on every external link on their own.
Detecting external links should be done entirely in CSS (here scoped to all links a
for simplicity):
a[href^="http"] {
...
}
The great thing is, you can also detect different protocols like for example mailto:
, to render an envelope symbol:
a[href^="mailto"] {
...
}
Custom Admonitions give a start how the mask-image approach can be pulled off :blush:
As I relayed earlier, the mask-image
approach wasn't working well for me. I was referencing your implementation for prev/next nav buttons at the bottom of a page though, the admonition example kinda works but needs adjustments otherwise:
This is due to using left
to offset with position: absolute
. Most notable is the nav tabs as all tabs are displaying the icon, but they've all been offset to the same location. Also the icons aren't clipped when you scroll down to the bottom of a page and the sidebar or toc is scrollable, the icons will overflow.
For the benefit of others that want to use the mask-image approach, you don't need to reference a font and unlike the background-image referencing an SVG, you can inherit the text colour with this approach:
/* Add this to your custom CSS file wrapped with an appropriate selector like discussed above */
content: "";
background-color: currentColor; /* inherit the relevant colour to match the text label */
padding-right: 0.6rem; /* width for SVG to fit into, affects scaling */
margin-right: 0.1rem; /* offset gap between icon and link label */
mask-position-y: 30%; /* vertically adjust Y position of icon to better place it */
mask-repeat: no-repeat;
mask-size: contain;
/* Add the SVG below (this one is the font-awesome external-link SVG sourced from `mkdocs-material/material/.icons/fontawesome/solid/external-link-alt.svg`) */
/* make sure it's encoded properly: https://yoksel.github.io/url-encoder/ */
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M432 320h-32a16 16 0 0 0-16 16v112H64V128h144a16 16 0 0 0 16-16V80a16 16 0 0 0-16-16H48a48 48 0 0 0-48 48v352a48 48 0 0 0 48 48h352a48 48 0 0 0 48-48V336a16 16 0 0 0-16-16zM488 0H360c-21.37 0-32.05 25.91-17 41l35.73 35.73L135 320.37a24 24 0 0 0 0 34L157.67 377a24 24 0 0 0 34 0l243.61-243.68L471 169c15 15 41 4.5 41-17V24a24 24 0 0 0-24-24z'/%3E%3C/svg%3E");
Bit more CSS and a little more fragile (doesn't scale with font size), but it might not be an issue for you. (EDIT: changing to em
units instead of rem
resolves that, eg padding-right: 0.8em; margin-right: 0.2em;
)
Detecting external links should be done entirely in CSS (here scoped to all links a for simplicity):
I covered this in the collapsed "Generic Selector" example. But you have to be careful as it can lead to unexpected targets like your twitter and github links in the Nav/announcement section on your project docs page.
That requires being more specific, often by maintaining a potentially long list of exclusions or inclusions as I mentioned.
I haven't read a compelling reason why we need that template switch. It's perfectly achievable with a few lines of CSS.
It has some minor benefits. I was advocating more towards upstream enablement via config, but perhaps I misunderstood the demographic of your users that you explained to me earlier.
I felt it's a common enough feature to centralize availability in upstream(this project) at least to a point that minimizes the expectations of a user to implement it, such as some documentation snippet at the very least.
Just for clarity, since this message will more than likely risk another CoC warning being issued. I fully understand that you aren't interested in making this an upstream feature. I don't care either way as it's a non-issue for me personally, but I do care about your community and I had them in mind.
Please forgive me if you feel my communication has been in any manner insulting, unprofessional, disrespectful, etc.
I must kindly remind you again to adhere to the code of conduct. This is your second warning (first one was here).
The first warning I asked for clarification but heard nothing back.
I'll take this 2nd warning as a sign that I should step away from this community. The sensitivity and misunderstandings of those whom enforce it is far too easy to trip over accidentally. While I have not contributed much to the community thus far, I'd rather not have anymore of my time and efforts disrespected; especially when it involves being threatened punishment for citing honest observations that someone in a position of authority disapproves of.
As a (dirty) workaround, I put the icon somewhere in the page, then inspect the element and copy the HTML of the span .twemoji, then I put it directly in the title:
# <span class="twemoji"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"></path></svg></span> Downloads
It won't work directly, you then need to fix some things in CSS
nav .twemoji {
display: inline-flex;
height: 1.125em;
width: 1.125em;
fill: currentColor;
vertical-align: text-top;
}
quick-and-dirty
solutionAnother way of simply adding an icon to the navigation (while keeping the formatting correct for both the tabs and the nav-bar) is as follows:
# file: mkdocs.yml
extra_javascript:
## for: fontawesome (use your own fontawesome kit)
- https://kit.fontawesome.com/1a2b3c4d5e.js # fontawesome-kit
nav:
# - Research: # instead of this use the following line
- "<p><i class='fas fa-flask'> </i> Research</p>":
- Paper2009: papers/paper2009.md
- Paper2012: papers/paper2012.md
- Paper2019: papers/paper2019.md
Granted, this makes the nav items a bit harder to read; but you can quickly get a dirty solution like this working. And may be later on if you have enough time and motivation, you could consider writing a plugin or contribute directly to mkdocs-material.
The fix here uses two things:
<p></p>
block.
inside the <i></i>
block to keep a space between the icon and the text (on the nav-bar).Sample Output:
This is how it would look like then (this is not the same code as the code-block above, but it uses the same logic/fix).
With
- "<p><i class='fab fa-stack-exchange'> </i> Teaching</p>":
as the section.
With
- "<i class='fab fa-stack-exchange'></i> Teaching":
as the section.
cc: @squidfunk @polarathene @Andre601
Update: navigation icons are now available.
Is there a way to use the navigation icons feature for nav tabs that are not associated with a MkDocs page (i.e., those that link to an external URL)?
You can make a redirect page and define a icon there. Example: https://codeberg.org/Andre601/AdvancedServerList/src/branch/master/docs/api/javadocs.md?display=source
Material for MkDocs provides the redirect.html
template already.
Sorry to chime in here, I know we don't get along 😅
This is mostly for the benefit of others dropping in here and to raise awareness to you and anyone else working on the project.
TL;DR:
9.5.5
unintentionally broke the endorsed CSS workaround to support external link icons for accessibility.FWIW, this concern raised a while back just recently happened and broke the rendering of the approach I had suggested and was endorsed over adding official support.
I didn't expect the breakage to be introduced in a point release, but it was from 9.5.5
, probably here.
Relative linkage was dropped, and I assume that's intentional given the changelog, so I don't know how you'd want to approach fixing the unintentional breakage here.
From the looks of it, I can workaround that with a less generic CSS rule:
.md-tabs__link[href]:not([href*="docker-mailserver.github.io"])::before, .md-nav__link[href]:not([href*="docker-mailserver.github.io"])::before
But that requires modification to support builds on deployment vs preview builds (different domains).
Alternatively, there is the other suggested approaches:
mkdocs.yml
entries by inserting HTML into the nav itemrel="noopener"
) that can be matched for external links by CSS instead. $7k monthly goal required to make that available to open-source projects.I don't make any money where I use mkdocs-material, so unfortunately I can't justify insiders in my circumstances.
The actual name is not "Navigation Icon", it's only discoverable via the "Reference" tab, or realizing the sidebar "Reference" is also a page link, then noticing the "Setting the page icon
" on the right-sidebar or scrolling down that reference main page.
One might think it'd be worthwhile to be discoverable from the navigation settings page, where there is no mention of icon. An example for a common enough case of marking an external link for added accessibility reasons would be nice to document, even if that's to convey to the reader that they cannot just provide an external nav link, but must add a markdown file to redirect to the external link to get the icon.
Perhaps the endorsed approach for marking external links in nav items is now the awkward approach with Navigation Icons and markdown file redirect workaround?
I haven't read a compelling reason why we need that template switch. It's perfectly achievable with a few lines of CSS. In fact, the CSS-only solution is superior
The CSS approach was justification for disregarding another request for this support officially. Where this article was endorsed as an example by @squidfunk on twitter for how to approach it.
However, like my examples shared here prior to that article being written, both depended upon href
attribute matching to differentiate from the relative links. Something that is no longer compatible going forward?
Thanks for your view on this.
I didn't expect the breakage to be introduced in a point release, but it was from 9.5.5, probably here.
So, first of all, you're talking about a customization, which is not considered public API surface, thus not a breaking change. If we would declare this a breaking change, we could only release major versions, because every change might be a breaking change, as we cannot possibly anticipate how authors customize the theme. Not economical, nor maintainable for us. We try to warn authors about changes to templates in our changelog though, none of which happened here.
Relative linkage was dropped, and I assume that's intentional given the changelog, so I don't know how you'd want to approach fixing the unintentional breakage here.
This is only the case if you enable navigation.instant
and it is done in the browser, meaning that HTML files are not touched, thus internal/external links are still detectable during build. We fixed all known bugs in instant navigation in 9.5.5, and making links absolute upon instant navigation is an absolute must, or things might break in certain situations. Especially on slow connections, which we tested with extensively, not replacing links sometimes led to wrong navigation, e.g.:
./foo
, URL changes immediately (read instant navigation code why this cannot be avoided)./bar
. If we would leave links relative, the resolved location would be ./foo/bar
now, which is incorrect.This is one of the main reasons I decided to make links absolute upon replacement of the document after instant navigation, as it now means that links are now always correct, regardless of connectivity. Additionally, if navigation fails completely for some reason, the application will try to navigate to the page regularly. All of this makes it necessary to canonicalize links before replacement. I invite you to study the instant navigation code, the reasoning is very heavily documented.
While I won't invest time to further discuss this change back and forth, because it is pointless given the bugs that desperately needed to be fixed, here are some workarounds:
navigation.instant
(simplest)rel=noopener
to detect, as noted – yes it is currently reserved to sponsors, but this is the canonical way we recommend. What you ask is by no means a critical feature, but optional, so it's perfectly fine to, for now, only provide this to sponsors.It's unfortunate that $13k monthly isn't sufficient for such a feature.
Okay. I'm going to explain it once and for all. You might not be aware of the fact that $13k a month is not what's going on my bank account. In fact, you can read in our sponsorship FAQ how we use funds. In short: sponsoring several upstream projects, sponsoring several MkDocs plugin maintainers, paying individuals that we add to our core team (we started to build a team), and taxes (a huge fraction, and yes, we also have to pay them). From the rest, I put bread on my table and dare to go on a vacation from time to time. I hope that is okay for you. Material for MkDocs currently is my day job, and we try to grow a sustainable ecosystem around it, adding more (wo)man power to cope with the increasing demand for change requests and user support, a large fraction notably by users that do not financially support us.
I'm going to leave it here and lock this thread now, because I've clearly explained the reasoning behind it and gave several possible workarounds. Please respect that. Thank you.
I want to suggest an idea and checked that ...
Description
It would be awesome, if it was doable to use both emojis and the pymdownx.emojis Icons in the navigation-section of the mkdocs.yml file. Right now does it not render those in the nav, limiting us a bit
Use Cases
This is useful for when you want to show icons in the nav to indicate certain things, such as the logo to a social media page, or - like in my case - indicate an external page with a external-link icon.
Screenshots / Mockups