diff --git a/app/router.scrollBehavior.js b/app/router.scrollBehavior.js new file mode 100644 index 0000000..75cbd35 --- /dev/null +++ b/app/router.scrollBehavior.js @@ -0,0 +1,80 @@ +<% if (router.scrollBehavior) { %> +<%= isTest ? '/* eslint-disable quotes, semi, indent, comma-spacing, key-spacing, object-curly-spacing, space-before-function-paren */' : '' %> +export default <%= serializeFunction(router.scrollBehavior) %> + <%= isTest ? '/* eslint-enable quotes, semi, indent, comma-spacing, key-spacing, object-curly-spacing, space-before-function-paren */' : '' %> + <% } else { %>import { getMatchedComponents } from './utils' + + if (process.client) { + if ('scrollRestoration' in window.history) { + window.history.scrollRestoration = 'manual' + + // reset scrollRestoration to auto when leaving page, allowing page reload + // and back-navigation from other pages to use the browser to restore the + // scrolling position. + window.addEventListener('beforeunload', () => { + window.history.scrollRestoration = 'auto' + }) + + // Setting scrollRestoration to manual again when returning to this page. + window.addEventListener('load', () => { + window.history.scrollRestoration = 'manual' + }) + } + } + +export default function (to, from, savedPosition) { + // if the returned position is falsy or an empty object, + // will retain current scroll position. + let position = false + + // if no children detected and scrollToTop is not explicitly disabled + const Pages = getMatchedComponents(to) + if ( + Pages.length < 2 && + Pages.every(Page => Page.options.scrollToTop !== false) + ) { + // scroll to the top of the page + position = { x: 0, y: 0 } + } else if (Pages.some(Page => Page.options.scrollToTop)) { + // if one of the children has scrollToTop option set to true + position = { x: 0, y: 0 } + } + + // savedPosition is only available for popstate navigations (back button) + if (savedPosition) { + position = savedPosition + } + + const nuxt = window.<%= globals.nuxt %> + + // triggerScroll is only fired when a new component is loaded + if (to.path === from.path && to.hash !== from.hash) { + nuxt.$nextTick(() => nuxt.$emit('triggerScroll')) + } + + return new Promise((resolve) => { + // wait for the out transition to complete (if necessary) + nuxt.$once('triggerScroll', () => { + // coords will be used if no selector is provided, + // or if the selector didn't match any element. + if (to.hash) { + let hash = to.hash + // CSS.escape() is not supported with IE and Edge. + if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') { + hash = '#' + window.CSS.escape(hash.substr(1)) + } + try { + if (document.querySelector(hash)) { + // scroll to anchor by returning the selector + position = { selector: hash, offset: {x:0, y: 100} } + } + } catch (e) { + <%= isTest ? '// eslint-disable-next-line no-console' : '' %> + console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).') + } + } + resolve(position) + }) + }) + } +<% } %> diff --git a/assets/css/_markdown-style.scss b/assets/css/_markdown-style.scss index 48fa98a..c5ab8ae 100644 --- a/assets/css/_markdown-style.scss +++ b/assets/css/_markdown-style.scss @@ -11,6 +11,20 @@ font-size: 1.3em; } + h2 { + margin-bottom: 10px; + margin-top: 30px; + + ~ h3 { + margin-top: 20px; + } + } + + + h3 { + font-size: .975em; + } + img { margin-top: 20px; margin-bottom: 20px; @@ -96,7 +110,11 @@ } a { - color: $NIGHT_BLUE + color: $NIGHT_BLUE; + + &.external-link { + color: $TERNARY_COLOR + } } blockquote { diff --git a/components/Editor/RichTextEditor.vue b/components/Editor/RichTextEditor.vue index 384b20a..8e22673 100644 --- a/components/Editor/RichTextEditor.vue +++ b/components/Editor/RichTextEditor.vue @@ -124,6 +124,14 @@ diff --git a/components/Menu.vue b/components/Menu.vue index 9f9bdfd..d43e776 100644 --- a/components/Menu.vue +++ b/components/Menu.vue @@ -35,24 +35,31 @@ Bibliothèque + + + + Tutoriel +