1
0
mirror of https://github.com/squidfunk/mkdocs-material.git synced 2024-11-28 01:10:58 +01:00

Refactored header autohiding and split overrides

This commit is contained in:
squidfunk 2021-02-12 15:44:53 +01:00
parent f7907fc09c
commit 28d507ecfe
28 changed files with 183 additions and 77 deletions

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,18 @@
{ {
"assets/javascripts/bundle.js": "assets/javascripts/bundle.7e5d1283.min.js", "assets/javascripts/bundle.js": "assets/javascripts/bundle.2bc3a92a.min.js",
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.7e5d1283.min.js.map", "assets/javascripts/bundle.js.map": "assets/javascripts/bundle.2bc3a92a.min.js.map",
"assets/javascripts/vendor.js": "assets/javascripts/vendor.9418a44e.min.js", "assets/javascripts/vendor.js": "assets/javascripts/vendor.6b8ac966.min.js",
"assets/javascripts/vendor.js.map": "assets/javascripts/vendor.9418a44e.min.js.map", "assets/javascripts/vendor.js.map": "assets/javascripts/vendor.6b8ac966.min.js.map",
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.b9424174.min.js", "assets/javascripts/worker/search.js": "assets/javascripts/worker/search.b9424174.min.js",
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.b9424174.min.js.map", "assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.b9424174.min.js.map",
"assets/stylesheets/main.css": "assets/stylesheets/main.c7b58751.min.css", "assets/stylesheets/main.css": "assets/stylesheets/main.6ced4fc6.min.css",
"assets/stylesheets/main.css.map": "assets/stylesheets/main.c7b58751.min.css.map", "assets/stylesheets/main.css.map": "assets/stylesheets/main.6ced4fc6.min.css.map",
"assets/stylesheets/palette.css": "assets/stylesheets/palette.d4a7bf42.min.css", "assets/stylesheets/palette.css": "assets/stylesheets/palette.e70b70b6.min.css",
"assets/stylesheets/palette.css.map": "assets/stylesheets/palette.d4a7bf42.min.css.map", "assets/stylesheets/palette.css.map": "assets/stylesheets/palette.e70b70b6.min.css.map",
"overrides/assets/javascripts/bundle.js": "overrides/assets/javascripts/bundle.75e3dcac.min.js", "overrides/assets/javascripts/bundle.js": "overrides/assets/javascripts/bundle.b79ba6f2.min.js",
"overrides/assets/javascripts/bundle.js.map": "overrides/assets/javascripts/bundle.75e3dcac.min.js.map", "overrides/assets/javascripts/bundle.js.map": "overrides/assets/javascripts/bundle.b79ba6f2.min.js.map",
"overrides/assets/stylesheets/main.css": "overrides/assets/stylesheets/main.dadc6109.min.css", "overrides/assets/javascripts/vendor.js": "overrides/assets/javascripts/vendor.1aa446d9.min.js",
"overrides/assets/stylesheets/main.css.map": "overrides/assets/stylesheets/main.dadc6109.min.css.map" "overrides/assets/javascripts/vendor.js.map": "overrides/assets/javascripts/vendor.1aa446d9.min.js.map",
"overrides/assets/stylesheets/main.css": "overrides/assets/stylesheets/main.8e98f424.min.css",
"overrides/assets/stylesheets/main.css.map": "overrides/assets/stylesheets/main.8e98f424.min.css.map"
} }

View File

@ -39,10 +39,10 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block styles %} {% block styles %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/main.c7b58751.min.css' | url }}"> <link rel="stylesheet" href="{{ 'assets/stylesheets/main.6ced4fc6.min.css' | url }}">
{% if config.theme.palette %} {% if config.theme.palette %}
{% set palette = config.theme.palette %} {% set palette = config.theme.palette %}
<link rel="stylesheet" href="{{ 'assets/stylesheets/palette.d4a7bf42.min.css' | url }}"> <link rel="stylesheet" href="{{ 'assets/stylesheets/palette.e70b70b6.min.css' | url }}">
{% if palette.primary %} {% if palette.primary %}
{% import "partials/palette.html" as map %} {% import "partials/palette.html" as map %}
{% set primary = map.primary( {% set primary = map.primary(
@ -191,7 +191,7 @@
"base": base_url, "base": base_url,
"features": features, "features": features,
"translations": {}, "translations": {},
"search": "assets/javascripts/worker/search.js" | url, "search": "assets/javascripts/worker/search.b9424174.min.js" | url,
} -%} } -%}
{%- set translations = app.translations -%} {%- set translations = app.translations -%}
{%- for key in [ {%- for key in [
@ -216,8 +216,8 @@
</script> </script>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<script src="{{ 'assets/javascripts/vendor.9418a44e.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/vendor.6b8ac966.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.7e5d1283.min.js' | url }}"></script> <script src="{{ 'assets/javascripts/bundle.2bc3a92a.min.js' | url }}"></script>
{% for path in config["extra_javascript"] %} {% for path in config["extra_javascript"] %}
<script src="{{ path | url }}"></script> <script src="{{ path | url }}"></script>
{% endfor %} {% endfor %}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
!function(e,t){for(var n in t)e[n]=t[n]}(window,function(e){function t(t){for(var r,i,a=t[0],s=t[1],u=t[2],f=0,p=[];f<a.length;f++)i=a[f],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(r in s)Object.prototype.hasOwnProperty.call(s,r)&&(e[r]=s[r]);for(l&&l(t);p.length;)p.shift()();return c.push.apply(c,u||[]),n()}function n(){for(var e,t=0;t<c.length;t++){for(var n=c[t],r=!0,a=1;a<n.length;a++){var s=n[a];0!==o[s]&&(r=!1)}r&&(c.splice(t--,1),e=i(i.s=n[0]))}return e}var r={},o={0:0},c=[];function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.m=e,i.c=r,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="";var a=window.webpackJsonp=window.webpackJsonp||[],s=a.push.bind(a);a.push=t,a=a.slice();for(var u=0;u<a.length;u++)t(a[u]);var l=s;return c.push([37,1]),n()}({37:function(e,t,n){"use strict";n.r(t);var r=n(20),o=n(3),c=n(38),i=n(45),a=n(29),s=n(25);n(32),n(39);function u(e,t=document){return t.querySelector(e)||void 0}function l(e,t=document){const n=u(e,t);if(void 0===n)throw new ReferenceError(`Missing element: expected "${e}" to be present`);return n}n(50);var f=n(51);var p=n(17),d=n(40),b=n(41),g=n(42),h=n(43),v=n(44);n(46);const O=new p.a;Object(d.a)(()=>Object(b.a)(new ResizeObserver(e=>{for(const t of e)O.next(t)}))).pipe(Object(a.a)(e=>g.a.pipe(Object(f.a)(e)).pipe(Object(h.a)(()=>e.disconnect()))),Object(v.a)(1));n(31);n(47);l("[data-md-toggle=drawer]"),l("[data-md-toggle=search]");n(52),n(53);n(48),n(49);function j(e,t){if("string"==typeof t||"number"==typeof t)e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(const n of t)j(e,n)}function m(e,t,...n){const r=document.createElement(e);if(t)for(const e of Object.keys(t))"boolean"!=typeof t[e]?r.setAttribute(e,t[e]):t[e]&&r.setAttribute(e,"");for(const e of n)j(r,e);return r}function y(e,t){return t.length?m("div",{class:""},m("span",null,function(e){if(e>999){return((e+1e-6)/1e3).toFixed(+((e-950)%1e3>99))+"k"}return e.toString()}(e.length)," results"),m("ul",{class:"tx-icon-search__list"},e.slice(0,10).map(e=>m("li",{class:"tx-icon-search__item"},m("span",{class:"twemoji"},m("img",{src:"https://raw.githubusercontent.com/squidfunk/mkdocs-material/master/material/.icons/"+e,style:"width: 18px; height: 18px"}))," ",m("button",{class:"md-clipboard--inline","data-clipboard-text":":"+e.replace(/\.svg$/,"").replace(/\//g,"-")+":"},m("code",null,function(e,t){return`:${Object(r.wrap)(e.replace(/\.svg$/,"").replace(/\//g,"-"),t,{wrap:{tagOpen:"<b>",tagClose:"</b>"}})}:`}(e,t))))))):m("div",{class:""})}const w=l("#__config"),x=JSON.parse(w.textContent),_=Object(o.a)(fetch(x.base+"/overrides/assets/javascripts/icons.json").then(e=>e.json())),k=u("#icon-search");k&&_.pipe(Object(i.a)(console.log),Object(a.a)(e=>Object(c.a)(k,"keyup").pipe(Object(s.a)(()=>Object(r.filter)(e,k.value))))).subscribe(e=>{const t=l(".tx-icon-result");t.innerHTML="",t.appendChild(y(e,k.value))}),Object(c.a)(document.body,"click").subscribe(e=>{if(e.target instanceof HTMLElement){e.target.closest("a[href^=http]")instanceof HTMLLinkElement&&ga("send","event","outbound","click",w.href)}})}}));
//# sourceMappingURL=bundle.b79ba6f2.min.js.map

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

@ -22,7 +22,7 @@
<meta name="twitter:title" content="{{ title }}"> <meta name="twitter:title" content="{{ title }}">
<meta name="twitter:description" content="{{ config.site_description }}"> <meta name="twitter:description" content="{{ config.site_description }}">
<meta name="twitter:image" content="{{ image }}"> <meta name="twitter:image" content="{{ image }}">
<link rel="stylesheet" href="{{ 'overrides/assets/stylesheets/main.dadc6109.min.css' | url }}"> <link rel="stylesheet" href="{{ 'overrides/assets/stylesheets/main.8e98f424.min.css' | url }}">
{% endblock %} {% endblock %}
{% block announce %} {% block announce %}
<a href="https://twitter.com/squidfunk"> <a href="https://twitter.com/squidfunk">
@ -53,14 +53,6 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
{{ super() }} {{ super() }}
{% block config %} <script src="{{ 'overrides/assets/javascripts/vendor.1aa446d9.min.js' | url }}"></script>
{%- set configuration = { <script src="{{ 'overrides/assets/javascripts/bundle.b79ba6f2.min.js' | url }}"></script>
"base": base_url,
"features": features
} -%}
<script id="__config" type="application/json">
{{- configuration | tojson -}}
</script>
{% endblock %}
<script src="{{ 'overrides/assets/javascripts/bundle.75e3dcac.min.js' | url }}"></script>
{% endblock %} {% endblock %}

View File

@ -21,23 +21,34 @@
*/ */
import { import {
NEVER,
Observable, Observable,
Subject, Subject,
animationFrameScheduler, animationFrameScheduler,
combineLatest,
defer, defer,
of of
} from "rxjs" } from "rxjs"
import { import {
bufferCount,
combineLatestWith, combineLatestWith,
distinctUntilChanged, distinctUntilChanged,
distinctUntilKeyChanged, distinctUntilKeyChanged,
filter,
map, map,
observeOn, observeOn,
shareReplay shareReplay,
startWith,
switchMap
} from "rxjs/operators" } from "rxjs/operators"
import { feature } from "~/_"
import { resetHeaderState, setHeaderState } from "~/actions" import { resetHeaderState, setHeaderState } from "~/actions"
import { Viewport, watchElementSize } from "~/browser" import {
Viewport,
watchElementSize,
watchToggle
} from "~/browser"
import { Component } from "../../_" import { Component } from "../../_"
import { Main } from "../../main" import { Main } from "../../main"
@ -50,14 +61,22 @@ import { Main } from "../../main"
* Header * Header
*/ */
export interface Header { export interface Header {
sticky: boolean /* Header stickyness */
height: number /* Header visible height */ height: number /* Header visible height */
sticky: boolean /* Header stickyness */
hidden: boolean /* User scrolled past threshold */
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Helper types * Helper types
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/**
* Watch options
*/
interface WatchOptions {
viewport$: Observable<Viewport> /* Viewport observable */
}
/** /**
* Mount options * Mount options
*/ */
@ -67,6 +86,52 @@ interface MountOptions {
main$: Observable<Main> /* Main area observable */ main$: Observable<Main> /* Main area observable */
} }
/* ----------------------------------------------------------------------------
* Helper functions
* ------------------------------------------------------------------------- */
/**
* Compute whether the header is hidden
*
* If the user scrolls past a certain threshold, the header can be hidden when
* scrolling down, and shown when scrolling up.
*
* @param options - Options
*
* @returns Toggle observable
*/
function isHidden({ viewport$ }: WatchOptions): Observable<boolean> {
if (!feature("header.autohide"))
return of(false)
/* Compute direction and turning point */
const direction$ = viewport$
.pipe(
map(({ offset: { y } }) => y),
bufferCount(2, 1),
map(([a, b]) => [a < b, b] as const),
distinctUntilKeyChanged(0)
)
/* Compute whether header should be hidden */
const hidden$ = combineLatest([viewport$, direction$])
.pipe(
filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),
map(([, [direction]]) => direction),
distinctUntilChanged(),
)
/* Compute threshold for autohiding */
const search$ = watchToggle("search")
return combineLatest([viewport$, search$])
.pipe(
map(([{ offset }, search]) => offset.y > 400 && !search),
distinctUntilChanged(),
switchMap(active => active ? hidden$ : NEVER),
startWith(false)
)
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Functions * Functions
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
@ -75,11 +140,12 @@ interface MountOptions {
* Watch header * Watch header
* *
* @param el - Header element * @param el - Header element
* @param options - Options
* *
* @returns Header observable * @returns Header observable
*/ */
export function watchHeader( export function watchHeader(
el: HTMLElement el: HTMLElement, options: WatchOptions
): Observable<Header> { ): Observable<Header> {
return defer(() => { return defer(() => {
const styles = getComputedStyle(el) const styles = getComputedStyle(el)
@ -89,14 +155,16 @@ export function watchHeader(
) )
}) })
.pipe( .pipe(
combineLatestWith(watchElementSize(el)), combineLatestWith(watchElementSize(el), isHidden(options)),
map(([sticky, { height }]) => ({ map(([sticky, { height }, hidden]) => ({
height: sticky ? height : 0,
sticky, sticky,
height: sticky ? height : 0 hidden
})), })),
distinctUntilChanged((a, b) => ( distinctUntilChanged((a, b) => (
a.sticky === b.sticky && a.sticky === b.sticky &&
a.height === b.height a.height === b.height &&
a.hidden === b.hidden
)), )),
shareReplay(1) shareReplay(1)
) )
@ -122,11 +190,12 @@ export function mountHeader(
internal$ internal$
.pipe( .pipe(
distinctUntilKeyChanged("active"), distinctUntilKeyChanged("active"),
combineLatestWith(header$),
observeOn(animationFrameScheduler) observeOn(animationFrameScheduler)
) )
.subscribe(({ active }) => { .subscribe(([{ active }, { hidden }]) => {
if (active) if (active)
setHeaderState(el, "shadow") setHeaderState(el, hidden ? "hidden" : "shadow")
else else
resetHeaderState(el) resetHeaderState(el)
}) })

View File

@ -88,7 +88,8 @@ if (feature("navigation.instant"))
/* Set up header observable */ /* Set up header observable */
const header$ = watchHeader( const header$ = watchHeader(
getElementOrThrow("[data-md-component=header]") getElementOrThrow("[data-md-component=header]"),
{ viewport$ }
) )
/* Set up main area observable */ /* Set up main area observable */
@ -153,6 +154,8 @@ const component$ = document$
mergeWith(control$) mergeWith(control$)
) )
component$.subscribe()
/* Export to window */ /* Export to window */
export { export {
document$, document$,

View File

@ -21,7 +21,6 @@
*/ */
/* eslint-disable */ /* eslint-disable */
import { filter } from "fuzzaldrin-plus" import { filter } from "fuzzaldrin-plus"
import { from, fromEvent } from "rxjs" import { from, fromEvent } from "rxjs"
import { map, switchMap } from "rxjs/operators" import { map, switchMap } from "rxjs/operators"

View File

@ -97,6 +97,7 @@
{{ super() }} {{ super() }}
<!-- Extra JavaScript --> <!-- Extra JavaScript -->
<script src="{{ 'overrides/assets/javascripts/vendor.js' | url }}"></script>
<script src="{{ 'overrides/assets/javascripts/bundle.js' | url }}"></script> <script src="{{ 'overrides/assets/javascripts/bundle.js' | url }}"></script>
{% endblock %} {% endblock %}

View File

@ -201,13 +201,9 @@ export default (_env: never, args: Configuration): Configuration[] => {
{ {
...base, ...base,
entry: { entry: {
"assets/javascripts/bundle": "src/assets/javascripts", "assets/javascripts/bundle": "src/assets/javascripts",
"assets/stylesheets/main": "src/assets/stylesheets/main.scss", "assets/stylesheets/main": "src/assets/stylesheets/main.scss",
"assets/stylesheets/palette": "src/assets/stylesheets/palette.scss", "assets/stylesheets/palette": "src/assets/stylesheets/palette.scss"
"overrides/assets/javascripts/bundle":
"src/overrides/assets/javascripts",
"overrides/assets/stylesheets/main":
"src/overrides/assets/stylesheets/main.scss"
}, },
output: { output: {
path: path.resolve(__dirname, "material"), path: path.resolve(__dirname, "material"),
@ -340,7 +336,10 @@ export default (_env: never, args: Configuration): Configuration[] => {
]) { ]) {
const template = toPairs<string>(manifest) const template = toPairs<string>(manifest)
.reduce((content, [from, to]) => ( .reduce((content, [from, to]) => (
content.replace(new RegExp(`'${from}'`, "g"), `'${to}'`) content.replace(new RegExp(
`('|")${from}\\1`, "g"),
`$1${to}$1`
)
), fs.readFileSync(file, "utf8")) ), fs.readFileSync(file, "utf8"))
/* Save template with replaced assets */ /* Save template with replaced assets */
@ -395,6 +394,44 @@ export default (_env: never, args: Configuration): Configuration[] => {
hashDigestLength: 8, hashDigestLength: 8,
libraryTarget: "var" libraryTarget: "var"
} }
},
/* Overrides */
{
...base,
entry: {
"overrides/assets/javascripts/bundle": "src/overrides/assets/javascripts",
"overrides/assets/stylesheets/main": "src/overrides/assets/stylesheets/main.scss"
},
output: {
path: path.resolve(__dirname, "material"),
filename: `[name]${hash}.js`,
hashDigestLength: 8,
libraryTarget: "window"
},
/* Plugins */
plugins: [
...base.plugins || [],
/* Stylesheets */
new MiniCssExtractPlugin({
filename: `[name]${hash}.css`
}),
],
/* Optimizations */
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "overrides/assets/javascripts/vendor",
chunks: "all"
}
}
}
}
} }
] ]
} }