diff --git a/.eslintrc b/.eslintrc index d5691ad3f..a88323e16 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,7 @@ { "extends": ["vue"], "globals": { - "XMLHttpRequest": true + "XMLHttpRequest": true, + "__docsify__": true } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 713d6f629..98aed1405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.0 +### Features +- Customize the theme color + ## 1.10.5 ### Bug fixes - fix initialize the Vue instance diff --git a/build/build-css.js b/build/build-css.js index 0890c2939..15af1d8e2 100644 --- a/build/build-css.js +++ b/build/build-css.js @@ -3,7 +3,15 @@ var cssnano = require('cssnano').process var resolve = require('path').resolve var postcss = require('postcss') -var processor = postcss([require('postcss-salad')]) +var processor = postcss([require('postcss-salad')({ + features: { + precss: { + properties: { + preserve: true + } + } + } +})]) var saveMin = function (file, content) { fs.writeFileSync(resolve(__dirname, '../lib/themes/', file), content) diff --git a/docs/README.md b/docs/README.md index e28164f66..e98939750 100644 --- a/docs/README.md +++ b/docs/README.md @@ -503,4 +503,17 @@ window.$docsify = { } ``` +### theme-color +Customize the theme color. + + +```html + +``` + +```js +window.$docsify = { + themeColor: '#3F51B5' +} +``` diff --git a/docs/zh-cn.md b/docs/zh-cn.md index da83dff47..0e48ea767 100644 --- a/docs/zh-cn.md +++ b/docs/zh-cn.md @@ -511,3 +511,17 @@ window.$docsify = { } ``` +### themeColor + +自定义主题色。 + + +```html + +``` + +```js +window.$docsify = { + themeColor: '#3F51B5' +} +``` diff --git a/src/index.js b/src/index.js index 233a830a4..716d73af7 100644 --- a/src/index.js +++ b/src/index.js @@ -17,6 +17,7 @@ const OPTIONS = merge({ basePath: '', auto2top: false, name: '', + themeColor: '', nameLink: window.location.pathname }, window.$docsify) const script = document.currentScript || [].slice.call(document.getElementsByTagName('script')).pop() @@ -35,6 +36,9 @@ if (script) { if (OPTIONS.sidebar) OPTIONS.sidebar = window[OPTIONS.sidebar] } +// utils +window.__docsify__ = OPTIONS + // load options render.init(OPTIONS) diff --git a/src/polyfill.js b/src/polyfill.js new file mode 100644 index 000000000..551499b7f --- /dev/null +++ b/src/polyfill.js @@ -0,0 +1,27 @@ +import { load } from './util' + +function replaceVar (block) { + block.innerHTML = block.innerHTML.replace(/var\(\s*--theme-color.*?\)/g, __docsify__.themeColor) +} + +export function cssVars () { + // variable support + if (window.CSS && window.CSS.supports && window.CSS.supports('(--foo: red)')) return + + const styleBlocks = document.querySelectorAll('style:not(.inserted),link') + + ;[].forEach.call(styleBlocks, block => { + if (block.nodeName === 'STYLE') { + replaceVar(block) + } else if (block.nodeName === 'LINK') { + load(block.getAttribute('href')) + .then(res => { + const style = document.createElement('style') + + style.innerHTML = res + document.head.appendChild(style) + replaceVar(style) + }) + } + }) +} diff --git a/src/render.js b/src/render.js index e73c38734..5ac5fdfbb 100644 --- a/src/render.js +++ b/src/render.js @@ -2,9 +2,9 @@ import marked from 'marked' import Prism from 'prismjs' import * as tpl from './tpl' import * as event from './event' +import * as polyfill from './polyfill' import { genTree, getRoute, isMobile, slugify, merge, emojify } from './util' -let OPTIONS = {} let markdown = marked let toc = [] const CACHE = {} @@ -19,11 +19,8 @@ const renderTo = function (dom, content) { /** * init render - * @param {Object} options */ -export function init (options) { - OPTIONS = options - +export function init () { const renderer = new marked.Renderer() /** * render anchor tag @@ -33,7 +30,7 @@ export function init (options) { const slug = slugify(text) let route = '' - if (OPTIONS.router) { + if (__docsify__.router) { route = `#/${getRoute()}` } @@ -48,7 +45,7 @@ export function init (options) { return `
${hl.replace(/:/g, '__colon__')}
` } renderer.link = function (href, title, text) { - if (OPTIONS.router && !/:/.test(href)) { + if (__docsify__.router && !/:/.test(href)) { href = `#/${href}`.replace(/\/\//g, '/') } @@ -63,11 +60,11 @@ export function init (options) { return `

${text}

` } - if (typeof OPTIONS.markdown === 'function') { + if (typeof __docsify__.markdown === 'function') { markdown.setOptions({ renderer }) - markdown = OPTIONS.markdown.call(this, markdown) + markdown = __docsify__.markdown.call(this, markdown) } else { - markdown.setOptions(merge({ renderer }, OPTIONS.markdown)) + markdown.setOptions(merge({ renderer }, __docsify__.markdown)) } const md = markdown @@ -81,17 +78,23 @@ export function init (options) { export function renderApp (dom, replace) { const nav = document.querySelector('nav') || document.createElement('nav') - if (!OPTIONS.repo) nav.classList.add('no-badge') + if (!__docsify__.repo) nav.classList.add('no-badge') - dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner(OPTIONS.repo) + - (OPTIONS.coverpage ? tpl.cover() : '') + - tpl.main(OPTIONS.sidebarToggle ? tpl.toggle() : '') + dom[replace ? 'outerHTML' : 'innerHTML'] = tpl.corner(__docsify__.repo) + + (__docsify__.coverpage ? tpl.cover() : '') + + tpl.main(__docsify__.sidebarToggle ? tpl.toggle() : '') document.body.insertBefore(nav, document.body.children[0]) + // theme color + if (__docsify__.themeColor) { + document.head.innerHTML += tpl.theme(__docsify__.themeColor) + polyfill.cssVars() + } + // bind toggle event.bindToggle('button.sidebar-toggle') // bind sticky effect - if (OPTIONS.coverpage) { + if (__docsify__.coverpage) { !isMobile() && window.addEventListener('scroll', event.sticky) } else { document.body.classList.add('sticky') @@ -103,7 +106,7 @@ export function renderApp (dom, replace) { */ export function renderArticle (content) { renderTo('article', content ? markdown(content) : 'not found') - if (!OPTIONS.sidebar && !OPTIONS.loadSidebar) renderSidebar() + if (!__docsify__.sidebar && !__docsify__.loadSidebar) renderSidebar() if (content && typeof Vue !== 'undefined') { CACHE.vm && CACHE.vm.$destroy() @@ -120,7 +123,7 @@ export function renderArticle (content) { : new Vue({ el: 'main' }) // eslint-disable-line CACHE.vm && CACHE.vm.$nextTick(_ => event.scrollActiveSidebar()) } - if (OPTIONS.auto2top) setTimeout(() => event.scroll2Top(OPTIONS.auto2top), 0) + if (__docsify__.auto2top) setTimeout(() => event.scroll2Top(__docsify__.auto2top), 0) } /** @@ -144,13 +147,13 @@ export function renderSidebar (content) { html = markdown(content) // find url tag html = html.match(/]*>([\s\S]+)<\/ul>/g)[0] - } else if (OPTIONS.sidebar) { - html = tpl.tree(OPTIONS.sidebar, '