1
0
mirror of https://github.com/squidfunk/mkdocs-material.git synced 2024-09-24 03:18:21 +02:00

Implemented source file linkage through metadata

This commit is contained in:
squidfunk 2017-03-11 14:07:07 +01:00 committed by Martin Donath
parent d12f17e520
commit 19fb287cef
24 changed files with 283 additions and 127 deletions

View File

@ -1,3 +1,15 @@
mkdocs-material-1.x.x (2017-xx-xx)
* Added possibility for non-fixed (static) header
* Added support for page-specific title and description using metadata
* Added support for the linking of source files to pages
* Fixed jitter and offset of sidebar when zooming browser
* Fixed incorrectly initialized tablet sidebar height
* Fixed regression for #1: GitHub stars break if the repo_url ends with a '/'
* Fixed undesired white line below copyright footer due to base font scaling
* Reduced repaints to a minimum for non-tabs configuration
* Slightly reduced contrast of edit button
mkdocs-material-1.2.0 (2017-03-03) mkdocs-material-1.2.0 (2017-03-03)
* Added quote (synonym: cite) style for Admonition * Added quote (synonym: cite) style for Admonition

View File

@ -48,8 +48,8 @@ export default (gulp, config, args) => {
removeScriptTypeAttributes: true, removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true removeStyleLinkTypeAttributes: true
})) }))
.pipe(replace("$theme-name$", metadata.name)) .pipe(replace("$md-name$", metadata.name))
.pipe(replace("$theme-version$", metadata.version)) .pipe(replace("$md-version$", metadata.version))
.pipe(compact()) .pipe(compact())
.pipe(gulpif(args.revision, .pipe(gulpif(args.revision,
version({ manifest: gulp.src("manifest.json") }))) version({ manifest: gulp.src("manifest.json") })))

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,13 +5,17 @@
{% block site_meta %} {% block site_meta %}
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
{% if config.site_description %} {% if page and page.meta.description %}
<meta name="description" content="{{ page.meta.description | first }}">
{% elif config.site_description %}
<meta name="description" content="{{ config.site_description }}"> <meta name="description" content="{{ config.site_description }}">
{% endif %} {% endif %}
{% if page.canonical_url %} {% if page.canonical_url %}
<link rel="canonical" href="{{ page.canonical_url }}"> <link rel="canonical" href="{{ page.canonical_url }}">
{% endif %} {% endif %}
{% if config.site_author %} {% if page and page.meta.author %}
<meta name="author" content="{{ page.meta.author | first }}">
{% elif config.site_author %}
<meta name="author" content="{{ config.site_author }}"> <meta name="author" content="{{ config.site_author }}">
{% endif %} {% endif %}
{% if config.site_favicon %} {% if config.site_favicon %}
@ -22,7 +26,9 @@
<meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-1.2.0"> <meta name="generator" content="mkdocs-{{ mkdocs_version }}, mkdocs-material-1.2.0">
{% endblock %} {% endblock %}
{% block htmltitle %} {% block htmltitle %}
{% if page.title and not page.is_homepage %} {% if page and page.meta.title %}
<title>{{ page.meta.title | first }}</title>
{% elif page and page.title and not page.is_homepage %}
<title>{{ page.title }} - {{ config.site_name }}</title> <title>{{ page.title }} - {{ config.site_name }}</title>
{% else %} {% else %}
<title>{{ config.site_name }}</title> <title>{{ config.site_name }}</title>
@ -32,9 +38,9 @@
<script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script> <script src="{{ base_url }}/assets/javascripts/modernizr-56ade86843.js"></script>
{% endblock %} {% endblock %}
{% block styles %} {% block styles %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-248e5b02e7.css"> <link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-a0d49b40f6.css">
{% if config.extra.palette %} {% if config.extra.palette %}
<link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-892b79c5c5.palette.css"> <link rel="stylesheet" href="{{ base_url }}/assets/stylesheets/application-66fa0d9bba.palette.css">
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block fonts %} {% block fonts %}
@ -112,39 +118,30 @@
{% if config.edit_uri %} {% if config.edit_uri %}
<a href="{{ page.edit_url }}" title="{{ lang.t('edit.link.title') }}" class="md-icon md-content__icon">edit</a> <a href="{{ page.edit_url }}" title="{{ lang.t('edit.link.title') }}" class="md-icon md-content__icon">edit</a>
{% endif %} {% endif %}
{% if page.meta.source %}
<a href="{{ page.edit_url }}" title="{{ lang.t('source.link.title') }}" class="md-icon md-content__icon">folder_open</a>
{% endif %}
{% if not "\x3ch1" in page.content %} {% if not "\x3ch1" in page.content %}
<h1>{{ page.title | default(config.site_name, true)}}</h1> <h1>{{ page.title | default(config.site_name, true)}}</h1>
{% endif %} {% endif %}
{{ page.content }} {{ page.content }}
{% if page.meta.source %} {% block source %}
<hr> {% if page.meta.source %}
<ul> <h2 id="__source">{{ lang.t('meta.source') }}</h2>
{% set path = (page.meta.path | default([""]) | first) %}
{% for file in page.meta.source %} {% for file in page.meta.source %}
<li><a href="#"><code>{{ file }}</code></a></li> <a href="{{
[repo_url, path, file] | join('/') | replace('//', '/')
}}" title="{{ file }}" class="md-source-file">
{{ file }}
</a>
{% endfor %} {% endfor %}
</ul> {% endif %}
{% endblock %}
{% endblock %}
{% block disqus %}
{% if config.extra.disqus and not page.is_homepage %}
<h2 id="__comments">{{ lang.t('meta.comments') }}</h2>
{% include "partials/disqus.html" %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% if config.extra.disqus and not page.is_homepage %}
<h2>{{ lang.t('comments') }}</h2>
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ page.canonical_url }}";
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
{% endif %}
</article> </article>
</div> </div>
</div> </div>
@ -154,7 +151,7 @@
{% endblock %} {% endblock %}
</div> </div>
{% block scripts %} {% block scripts %}
<script src="{{ base_url }}/assets/javascripts/application-3873210def.js"></script> <script src="{{ base_url }}/assets/javascripts/application-7aa26ad9ec.js"></script>
<script>app.initialize({url:{base:"{{ base_url }}"}})</script> <script>app.initialize({url:{base:"{{ base_url }}"}})</script>
{% for path in extra_javascript %} {% for path in extra_javascript %}
<script src="{{ path }}"></script> <script src="{{ path }}"></script>

View File

@ -0,0 +1,14 @@
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ page.canonical_url }}";
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

View File

@ -1,8 +1,9 @@
{% macro t(key) %}{{ { {% macro t(key) %}{{ {
"edit.link.title": "Edit this page", "edit.link.title": "Edit this page",
"comments": "Comments",
"footer.previous": "Previous", "footer.previous": "Previous",
"footer.next": "Next", "footer.next": "Next",
"meta.comments": "Comments",
"meta.source": "Source",
"search.placeholder": "Search", "search.placeholder": "Search",
"source.link.title": "Go to repository", "source.link.title": "Go to repository",
"toc.title": "Table of contents" "toc.title": "Table of contents"

View File

@ -10,6 +10,20 @@
{% for toc_item in toc_ %} {% for toc_item in toc_ %}
{% include "partials/toc-item.html" %} {% include "partials/toc-item.html" %}
{% endfor %} {% endfor %}
{% if page.meta.source and page.meta.source | length > 0 %}
<li class="md-nav__item">
<a href="#__source" title="{{ lang.t('meta.source') }}" class="md-nav__link md-nav__link--active">
{{ lang.t('meta.source') }}
</a>
</li>
{% endif %}
{% if config.extra.disqus and not page.is_homepage %}
<li class="md-nav__item">
<a href="#__comments" title="{{ lang.t('meta.comments') }}" class="md-nav__link md-nav__link--active">
{{ lang.t('meta.comments') }}
</a>
</li>
{% endif %}
</ul> </ul>
{% endif %} {% endif %}
</nav> </nav>

View File

@ -107,13 +107,7 @@ function initialize(config) { // eslint-disable-line func-style
/* Component: sidebar with table of contents - register two separate /* Component: sidebar with table of contents - register two separate
listeners, as the offset at the top might change */ listeners, as the offset at the top might change */
new Material.Event.MatchMedia("(min-width: 960px) and (max-width: 1219px)", new Material.Event.MatchMedia("(min-width: 960px)",
new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange"
], new Material.Sidebar.Position(
"[data-md-component=toc]",
"[data-md-component=header]")))
new Material.Event.MatchMedia("(min-width: 1220px)",
new Material.Event.Listener(window, [ new Material.Event.Listener(window, [
"scroll", "resize", "orientationchange" "scroll", "resize", "orientationchange"
], new Material.Sidebar.Position( ], new Material.Sidebar.Position(

View File

@ -36,6 +36,7 @@ export default class Position {
* @property {HTMLElement} header_ - Header * @property {HTMLElement} header_ - Header
* @property {number} height_ - Current sidebar height * @property {number} height_ - Current sidebar height
* @property {number} offset_ - Current page y-offset * @property {number} offset_ - Current page y-offset
* @property {boolean} pad_ - Pad when header is fixed
* *
* @param {(string|HTMLElement)} el - Selector or HTML element * @param {(string|HTMLElement)} el - Selector or HTML element
* @param {(string|HTMLElement)} header - Selector or HTML element * @param {(string|HTMLElement)} header - Selector or HTML element
@ -58,8 +59,9 @@ export default class Position {
throw new ReferenceError throw new ReferenceError
this.header_ = ref this.header_ = ref
/* Initialize current height */ /* Initialize current height and test whether header is fixed */
this.height_ = 0 this.height_ = 0
this.pad_ = window.getComputedStyle(this.header_).position === "fixed"
} }
/** /**
@ -72,7 +74,7 @@ export default class Position {
}, 0) }, 0)
/* Set lock offset for element with largest top offset */ /* Set lock offset for element with largest top offset */
this.offset_ = top - this.header_.offsetHeight this.offset_ = top - (this.pad_ ? this.header_.offsetHeight : 0)
this.update() this.update()
} }
@ -98,7 +100,7 @@ export default class Position {
/* Set bounds of sidebar container - must be calculated on every run, as /* Set bounds of sidebar container - must be calculated on every run, as
the height of the content might change due to loading images etc. */ the height of the content might change due to loading images etc. */
const bounds = { const bounds = {
top: this.header_.offsetHeight, top: this.pad_ ? this.header_.offsetHeight : 0,
bottom: this.parent_.offsetTop + this.parent_.offsetHeight bottom: this.parent_.offsetTop + this.parent_.offsetHeight
} }

View File

@ -37,8 +37,10 @@ export default class GitHub extends Abstract {
constructor(el) { constructor(el) {
super(el) super(el)
/* Adjust base URL to reach API endpoints */ /* Adjust base URL to reach API endpoints and remove trailing slash */
this.base_ = this.base_.replace("github.com/", "api.github.com/repos/") this.base_ = this.base_
.replace("github.com/", "api.github.com/repos/")
.replace(/\/$/, "")
} }
/** /**

View File

@ -233,5 +233,10 @@ button[data-md-color-accent] {
.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover { .md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover {
background-color: $color; background-color: $color;
} }
// Source file icon
.md-source-file:hover::before {
background-color: $color;
}
} }
} }

View File

@ -60,38 +60,19 @@
@extend %md-icon__button; @extend %md-icon__button;
position: relative; position: relative;
margin-top: 0.8rem; margin: 0.8rem 0;
padding-right: 0;
padding-left: 0;
float: right; float: right;
// TODO // Override default link color for icons
html body .md-typeset & { html body .md-typeset & {
color: $md-color-black--lighter; color: $md-color-black--lighter;
} }
// [tablet portrait -]: Align edit link with search icon
@include break-to-device(tablet portrait) {
margin-right: -0.8rem;
// TODO
& + & {
margin-right: 0.4rem;
}
}
// Hide for print // Hide for print
@media print { @media print {
display: none; display: none;
} }
// TODO
& + &::before {
display: block;
position: absolute;
top: -0.4rem;
right: -0.5rem;
height: 4.8rem;
border-right: 0.2rem solid $md-color-black--lighter;
content: "";
}
} }
} }

View File

@ -116,6 +116,8 @@
// Set spacing // Set spacing
&__inner { &__inner {
// Hack: omit subpixel rounding issues when scaling up the base font
margin-bottom: -0.1rem;
padding: 0.4rem; padding: 0.4rem;
overflow: auto; overflow: auto;
} }

View File

@ -33,6 +33,11 @@
&--secondary { &--secondary {
transition: border-left 0.25s; transition: border-left 0.25s;
border-left: 0.4rem solid $md-color-primary; border-left: 0.4rem solid $md-color-primary;
// Highlight active links (used for page-related meta navigation)
.md-nav__link--active {
color: $md-color-primary;
}
} }
// List title // List title
@ -309,28 +314,38 @@
} }
} }
// Set nested navigation for table of contents to static // Table of contents inside navigation
.md-nav--secondary .md-nav { .md-nav--secondary {
position: static;
// 3rd level link // Set links to static to avoid unnecessary layering
.md-nav__link { .md-nav__link {
padding-left: 2.8rem; position: static;
} }
// 4th level link // Set nested navigation for table of contents to static
.md-nav .md-nav__link { .md-nav {
padding-left: 4rem; position: static;
} background-color: transparent;
// 5th level link // 3rd level link
.md-nav .md-nav .md-nav__link { .md-nav__link {
padding-left: 5.2rem; padding-left: 2.8rem;
} }
// 6th level link // 4th level link
.md-nav .md-nav .md-nav .md-nav__link { .md-nav .md-nav__link {
padding-left: 6.4rem; padding-left: 4rem;
}
// 5th level link
.md-nav .md-nav .md-nav__link {
padding-left: 5.2rem;
}
// 6th level link
.md-nav .md-nav .md-nav .md-nav__link {
padding-left: 6.4rem;
}
} }
} }
} }

View File

@ -149,3 +149,60 @@
} }
} }
} }
// Source file
.md-source-file {
display: inline-block;
margin: 1em 0.5em 1em 0;
padding-right: 0.5rem;
border-radius: 0.2rem;
background: $md-color-black--lightest;
font-size: ms(-1);
list-style-type: none;
cursor: pointer;
overflow: hidden;
// Icon
&::before {
@extend %md-icon;
display: inline-block;
margin-right: 0.5rem;
padding: 0.5rem;
background: $md-color-black--lighter;
color: $md-color-white;
font-size: ms(0);
content: "clear_all";
vertical-align: middle;
}
// Some properties need to be set with higher specificity due to the default
// styling of text links inside typesetted content
html & {
transition:
background 0.4s,
color 0.4s,
box-shadow 0.4s cubic-bezier(0.4, 0, 0.2, 1);
// Icon
&::before {
transition: inherit;
}
}
// Color needs even higher specifity because custom color palettes are set
// using the body and override text links inside typesetted content
html body .md-typeset & {
color: $md-color-black--light;
}
// Hovered source file
&:hover {
@include z-depth-focus;
// Icon
&::before {
background: $md-color-accent;
}
}
}

View File

@ -31,8 +31,11 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Site description --> <!-- Page description -->
{% if config.site_description %} {% if page and page.meta.description %}
<meta name="description"
content="{{ page.meta.description | first }}" />
{% elif config.site_description %}
<meta name="description" content="{{ config.site_description }}" /> <meta name="description" content="{{ config.site_description }}" />
{% endif %} {% endif %}
@ -41,8 +44,10 @@
<link rel="canonical" href="{{ page.canonical_url }}" /> <link rel="canonical" href="{{ page.canonical_url }}" />
{% endif %} {% endif %}
<!-- Author --> <!-- Page author -->
{% if config.site_author %} {% if page and page.meta.author %}
<meta name="author" content="{{ page.meta.author | first }}" />
{% elif config.site_author %}
<meta name="author" content="{{ config.site_author }}" /> <meta name="author" content="{{ config.site_author }}" />
{% endif %} {% endif %}
@ -57,12 +62,14 @@
<!-- Generator banner --> <!-- Generator banner -->
<meta name="generator" <meta name="generator"
content="mkdocs-{{ mkdocs_version }}, $theme-name$-$theme-version$" /> content="mkdocs-{{ mkdocs_version }}, $md-name$-$md-version$" />
{% endblock %} {% endblock %}
<!-- Block: site title --> <!-- Block: site title -->
{% block htmltitle %} {% block htmltitle %}
{% if page.title and not page.is_homepage %} {% if page and page.meta.title %}
<title>{{ page.meta.title | first }}</title>
{% elif page and page.title and not page.is_homepage %}
<title>{{ page.title }} - {{ config.site_name }}</title> <title>{{ page.title }} - {{ config.site_name }}</title>
{% else %} {% else %}
<title>{{ config.site_name }}</title> <title>{{ config.site_name }}</title>
@ -220,13 +227,6 @@
class="md-icon md-content__icon">edit</a> class="md-icon md-content__icon">edit</a>
{% endif %} {% endif %}
<!-- Linked source files -->
{% if page.meta.source %}
<a href="{{ page.edit_url }}"
title="{{ lang.t('source.link.title') }}"
class="md-icon md-content__icon">folder_open</a>
{% endif %}
<!-- <!--
Hack: check whether the content contains a h1 headline. If it Hack: check whether the content contains a h1 headline. If it
doesn't, the page title (or respectively site name) is used doesn't, the page title (or respectively site name) is used
@ -239,34 +239,36 @@
<!-- Content --> <!-- Content -->
{{ page.content }} {{ page.content }}
{% if page.meta.source %} <!-- Source files -->
<hr> {% block source %}
<ul> {% if page.meta.source %}
<h2 id="__source">{{ lang.t('meta.source') }}</h2>
{% set path = (page.meta.path | default([""]) | first) %}
{% for file in page.meta.source %} {% for file in page.meta.source %}
<li><a href="#"><code>{{ file }}</code></a></li>
<!--
Hack: here, we just glue all parts of the source file
path together, ensure that there are slashes and remove
double slashes afterwards. Not beautiful, but it will
catch a lot of use cases.
-->
<a href="{{
[repo_url, path, file] | join('/') | replace('//', '/')
}}" title="{{ file }}" class="md-source-file">
{{ file }}
</a>
{% endfor %} {% endfor %}
</ul> {% endif %}
{% endif %} {% endblock %}
{% endblock %} {% endblock %}
<!-- Disqus integration --> <!-- Disqus integration -->
{% if config.extra.disqus and not page.is_homepage %} {% block disqus %}
<h2>{{ lang.t('comments') }}</h2> {% if config.extra.disqus and not page.is_homepage %}
<div id="disqus_thread"></div> <h2 id="__comments">{{ lang.t('meta.comments') }}</h2>
<script> {% include "partials/disqus.html" %}
var disqus_config = function () { {% endif %}
this.page.url = "{{ page.canonical_url }}"; {% endblock %}
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
{% endif %}
</article> </article>
</div> </div>
</div> </div>

37
src/partials/disqus.html Normal file
View File

@ -0,0 +1,37 @@
<!--
Copyright (c) 2016-2017 Martin Donath <martin.donath@squidfunk.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
-->
<!-- Disqus integration -->
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = "{{ page.canonical_url }}";
this.page.identifier =
"{{ page.canonical_url | replace(config.site_url, "") }}";
};
(function() {
var d = document, s = d.createElement("script");
s.src = "//{{ config.extra.disqus }}.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
})();
</script>

View File

@ -23,9 +23,10 @@
<!-- Translations --> <!-- Translations -->
{% macro t(key) %}{{ { {% macro t(key) %}{{ {
"edit.link.title": "Edit this page", "edit.link.title": "Edit this page",
"comments": "Comments",
"footer.previous": "Previous", "footer.previous": "Previous",
"footer.next": "Next", "footer.next": "Next",
"meta.comments": "Comments",
"meta.source": "Source",
"search.placeholder": "Search", "search.placeholder": "Search",
"source.link.title": "Go to repository", "source.link.title": "Go to repository",
"toc.title": "Table of contents" "toc.title": "Table of contents"

View File

@ -43,6 +43,26 @@
{% for toc_item in toc_ %} {% for toc_item in toc_ %}
{% include "partials/toc-item.html" %} {% include "partials/toc-item.html" %}
{% endfor %} {% endfor %}
<!-- Source files -->
{% if page.meta.source and page.meta.source | length > 0 %}
<li class="md-nav__item">
<a href="#__source" title="{{ lang.t('meta.source') }}"
class="md-nav__link md-nav__link--active">
{{ lang.t('meta.source') }}
</a>
</li>
{% endif %}
<!-- Disqus integration -->
{% if config.extra.disqus and not page.is_homepage %}
<li class="md-nav__item">
<a href="#__comments" title="{{ lang.t('meta.comments') }}"
class="md-nav__link md-nav__link--active">
{{ lang.t('meta.comments') }}
</a>
</li>
{% endif %}
</ul> </ul>
{% endif %} {% endif %}
</nav> </nav>