From 0d0b6b0a322d43f7e61ed68a6ef8c0319ad19e4c Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 24 May 2016 10:17:32 +0800 Subject: [PATCH] site: update --- bisheng.config.js | 9 ++ components/icon/index.md | 2 +- docs/spec/colors.md | 1 + docs/spec/layout/demo/aside-collapse.md | 2 +- docs/spec/layout/demo/aside.md | 2 +- docs/spec/layout/demo/ceiling.md | 2 +- docs/spec/layout/demo/top-aside.md | 2 +- docs/spec/layout/demo/top.md | 2 +- package.json | 2 + site/bisheng-markdown-react-loader/index.js | 58 ++++++++ site/bisheng-plugin-antd/lib/process-demo.js | 24 +++- site/bisheng-plugin-antd/lib/process-doc.js | 12 +- site/entry/index.jsx | 131 ------------------ site/entry/utils.js | 120 ---------------- .../styles => theme/static}/colors.less | 0 .../styles => theme/static}/mock-browser.less | 0 .../static}/new-version-info-modal.less | 0 site/theme/static/style.js | 3 + .../template/BrowserDemo.jsx} | 0 site/theme/template/Content/ComponentDoc.jsx | 2 +- site/theme/template/Content/Demo.jsx | 9 +- .../template}/IconSet/CopyableIcon.jsx | 0 .../template}/IconSet/index.jsx | 0 23 files changed, 113 insertions(+), 270 deletions(-) create mode 100644 site/bisheng-markdown-react-loader/index.js delete mode 100644 site/entry/index.jsx delete mode 100644 site/entry/utils.js rename site/{common/styles => theme/static}/colors.less (100%) rename site/{common/styles => theme/static}/mock-browser.less (100%) rename site/{common/styles => theme/static}/new-version-info-modal.less (100%) rename site/{component/BrowserDemo/index.jsx => theme/template/BrowserDemo.jsx} (100%) rename site/{component => theme/template}/IconSet/CopyableIcon.jsx (100%) rename site/{component => theme/template}/IconSet/index.jsx (100%) diff --git a/bisheng.config.js b/bisheng.config.js index e8fbdc1d04..01d8e73486 100644 --- a/bisheng.config.js +++ b/bisheng.config.js @@ -1,3 +1,5 @@ +const path = require('path'); + module.exports = { source: ['./components', './docs'], theme: './site/theme', @@ -7,10 +9,17 @@ module.exports = { './site/bisheng-plugin-antd', ], webpackConfig(config) { + config.resolve.root = process.cwd(); config.resolve.alias = { antd: process.cwd(), + site: 'site', }; + config.module.loaders.forEach((loader) => { + if (loader.test.toString() !== '/\\.md$/') return; + loader.loaders.splice(1, 0, path.join(process.cwd(), 'site/bisheng-markdown-react-loader')); + }); + config.babel.plugins.push([ require.resolve('babel-plugin-antd'), { diff --git a/components/icon/index.md b/components/icon/index.md index 2dc7a75b52..033b12f90e 100644 --- a/components/icon/index.md +++ b/components/icon/index.md @@ -40,7 +40,7 @@ english: Icon ### 一. 方向性图标 ```__react -import IconSet from '../../site/component/IconSet'; +import IconSet from 'site/theme/template/IconSet'; const icons1 = ['step-backward', 'step-forward', 'fast-backward', 'fast-forward', 'shrink', 'arrow-salt', 'down', 'up', 'left', 'right', 'caret-down', 'caret-up', 'caret-left', 'caret-right', 'caret-circle-right', 'caret-circle-left', 'caret-circle-o-right', 'caret-circle-o-left', 'circle-right', 'circle-left', 'circle-o-right', 'circle-o-left', 'double-right', 'double-left', 'verticle-right', 'verticle-left', 'forward', 'backward', 'rollback', 'enter', 'retweet', 'swap', 'swap-left', 'swap-right', 'arrow-right', 'arrow-up', 'arrow-down', 'arrow-left', 'play-circle', 'play-circle-o', 'circle-up', 'circle-down', 'circle-o-up', 'circle-o-down', 'caret-circle-o-up', 'caret-circle-o-down', 'caret-circle-up', 'caret-circle-down']; ReactDOM.render(, mountNode); diff --git a/docs/spec/colors.md b/docs/spec/colors.md index 9a9e0f84ab..03d74f5d36 100644 --- a/docs/spec/colors.md +++ b/docs/spec/colors.md @@ -157,6 +157,7 @@ ReactDOM.render(, mountNode); `````__react const Values = require('values.js'); const CopyToClipboard = require('react-copy-to-clipboard'); +const antd = require('antd'); const Button = antd.Button; const InputNumber = antd.InputNumber; const Slider = antd.Slider; diff --git a/docs/spec/layout/demo/aside-collapse.md b/docs/spec/layout/demo/aside-collapse.md index c5ac3500be..d61761200e 100644 --- a/docs/spec/layout/demo/aside-collapse.md +++ b/docs/spec/layout/demo/aside-collapse.md @@ -7,7 +7,7 @@ title: 可收起展开的侧边导航 ````jsx import { Menu, Breadcrumb, Icon } from 'antd'; -import BrowserDemo from 'site/component/BrowserDemo'; +import BrowserDemo from 'site/theme/template/BrowserDemo'; const SubMenu = Menu.SubMenu; const AsideCollapse = React.createClass({ diff --git a/docs/spec/layout/demo/aside.md b/docs/spec/layout/demo/aside.md index f6ad090b5b..f1d00763b7 100644 --- a/docs/spec/layout/demo/aside.md +++ b/docs/spec/layout/demo/aside.md @@ -9,7 +9,7 @@ title: 侧边导航 ````jsx import { Menu, Breadcrumb, Icon } from 'antd'; -import BrowserDemo from 'site/component/BrowserDemo'; +import BrowserDemo from 'site/theme/template/BrowserDemo'; const SubMenu = Menu.SubMenu; ReactDOM.render( diff --git a/docs/spec/layout/demo/ceiling.md b/docs/spec/layout/demo/ceiling.md index 97822900dd..2b15ce835c 100644 --- a/docs/spec/layout/demo/ceiling.md +++ b/docs/spec/layout/demo/ceiling.md @@ -9,7 +9,7 @@ title: 吊顶规范 ````jsx import { Menu, Breadcrumb } from 'antd'; -import BrowserDemo from 'site/component/BrowserDemo'; +import BrowserDemo from 'site/theme/template/BrowserDemo'; ReactDOM.render( diff --git a/docs/spec/layout/demo/top-aside.md b/docs/spec/layout/demo/top-aside.md index 6fe494f1c3..4295dbaead 100644 --- a/docs/spec/layout/demo/top-aside.md +++ b/docs/spec/layout/demo/top-aside.md @@ -7,7 +7,7 @@ title: 顶部导航 + 侧边栏 ````jsx import { Menu, Breadcrumb, Icon } from 'antd'; -import BrowserDemo from 'site/component/BrowserDemo'; +import BrowserDemo from 'site/theme/template/BrowserDemo'; const SubMenu = Menu.SubMenu; ReactDOM.render( diff --git a/docs/spec/layout/demo/top.md b/docs/spec/layout/demo/top.md index f7e3ead9fd..c9d942c012 100644 --- a/docs/spec/layout/demo/top.md +++ b/docs/spec/layout/demo/top.md @@ -11,7 +11,7 @@ title: 顶部导航 ````jsx import { Menu, Breadcrumb } from 'antd'; -import BrowserDemo from 'site/component/BrowserDemo'; +import BrowserDemo from 'site/theme/template/BrowserDemo'; ReactDOM.render( diff --git a/package.json b/package.json index 76d28c9046..e17d068c72 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "eslint-plugin-markdown": "*", "eslint-plugin-react": "^5.0.1", "eslint-tinker": "^0.3.1", + "esprima-fb": "^15001.1001.0-dev-harmony-fb", "history": "^2.0.1", "intl": "^1.2.2", "intl-locales-supported": "^1.0.0", @@ -113,6 +114,7 @@ "react-router": "^2.0.0", "react-stateless-wrapper": "^1.0.2", "react-sublime-video": "^0.2.0-beta", + "recast": "^0.11.5", "reqwest": "^2.0.5", "values.js": "^1.0.3", "webpack-babel-jest": "^1.0.4" diff --git a/site/bisheng-markdown-react-loader/index.js b/site/bisheng-markdown-react-loader/index.js new file mode 100644 index 0000000000..a138bd0ece --- /dev/null +++ b/site/bisheng-markdown-react-loader/index.js @@ -0,0 +1,58 @@ +'use strict'; +const recast = require('recast'); +const builders = recast.types.builders; + +// WAITING: esprima will support JSX +const parseOptions = { + parser: require('esprima-fb'), +}; + +function isImport(node) { + return node.type === 'ImportDeclaration'; +} +function isNotImport(node) { + return !isImport(node); +} + +module.exports = (content) => { + if (this.cacheable) { + this.cacheable(); + } + + let imports = []; + const ast = recast.visit(recast.parse(content, parseOptions), { + visitArrayExpression(path) { + const node = path.node; + + const firstItem = node.elements[0]; + const secondItem = node.elements[1]; + + if (firstItem && + firstItem.type === 'Literal' && + firstItem.value === 'pre' && + secondItem.properties[0].value.value === '__react') { // TODO + const codeAst = recast.parse(node.elements[2].elements[1].value, parseOptions); + const astProgramBody = codeAst.program.body; + + const codeImports = astProgramBody.filter(isImport); + imports = imports.concat(codeImports); + + const codeBody = astProgramBody.filter(isNotImport); + const lastIndex = codeBody.length - 1; + codeBody[lastIndex] = builders.returnStatement( + codeBody[lastIndex].expression.arguments[0] + ); + + return builders.functionExpression(null, [ + builders.identifier('React'), // TODO + builders.identifier('ReactDOM'), + ], builders.blockStatement(codeBody)); + } + + this.traverse(path); + }, + }); + + ast.program.body = imports.concat(ast.program.body); + return recast.print(ast).code; +}; diff --git a/site/bisheng-plugin-antd/lib/process-demo.js b/site/bisheng-plugin-antd/lib/process-demo.js index 4df8a57fa2..f42018acf8 100644 --- a/site/bisheng-plugin-antd/lib/process-demo.js +++ b/site/bisheng-plugin-antd/lib/process-demo.js @@ -1,5 +1,15 @@ const JsonML = require('jsonml.js/lib/utils'); +function isStyleTag(node) { + return node && JsonML.getTagName(node) === 'style'; +} + +function getCode(node) { + return JsonML.getChildren( + JsonML.getChildren(node)[0] + )[0]; +} + module.exports = (markdownData) => { const meta = markdownData.meta; meta.id = meta.filename.replace(/\.md$/, '').replace(/\//g, '-'); @@ -26,13 +36,19 @@ module.exports = (markdownData) => { markdownData.content = contentChildren.slice(0, codeIndex); } - markdownData.code = contentChildren[codeIndex]; + markdownData.highlightedCode = contentChildren[codeIndex].slice(0, 2); + markdownData.preview = [ + 'pre', { lang: '__react' }, + ].concat(JsonML.getChildren(contentChildren[codeIndex])); const styleNode = contentChildren.find((node) => { - return JsonML.getTagName(node) === 'pre' && - JsonML.getAttributes(node).lang === 'css'; + return isStyleTag(node) || + (JsonML.getTagName(node) === 'pre' && JsonML.getAttributes(node).lang === 'css'); }); - if (styleNode) { + if (isStyleTag(styleNode)) { + markdownData.style = JsonML.getChildren(styleNode)[0]; + } else if (styleNode) { + markdownData.style = getCode(styleNode); markdownData.highlightedStyle = JsonML.getAttributes(styleNode).highlighted; } diff --git a/site/bisheng-plugin-antd/lib/process-doc.js b/site/bisheng-plugin-antd/lib/process-doc.js index 940d892c45..a4358c1e42 100644 --- a/site/bisheng-plugin-antd/lib/process-doc.js +++ b/site/bisheng-plugin-antd/lib/process-doc.js @@ -6,10 +6,14 @@ module.exports = (markdownData) => { return JsonML.getTagName(node) === 'h2' && JsonML.getChildren(node)[0] === 'API'; }); - const content = contentChildren.slice(0, apiStartIndex); - const api = contentChildren.slice(apiStartIndex); - markdownData.content = ['section'].concat(content); - markdownData.api = ['section'].concat(api); + if (apiStartIndex > -1) { + const content = contentChildren.slice(0, apiStartIndex); + markdownData.content = ['section'].concat(content); + + const api = contentChildren.slice(apiStartIndex); + markdownData.api = ['section'].concat(api); + } + return markdownData; }; diff --git a/site/entry/index.jsx b/site/entry/index.jsx deleted file mode 100644 index cf53a5209a..0000000000 --- a/site/entry/index.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { addLocaleData, IntlProvider } from 'react-intl'; -import { Router, Route, IndexRoute, Redirect, useRouterHistory } from 'react-router'; -import antd from '../../index.js'; -import * as utils from './utils'; -import '../common/lib'; -import App from '../component/App'; -import Home from '../component/Home/index'; -import NotFound from '../component/NotFound/index'; -import practice from '../../_data/practice'; -import pattern from '../../_data/pattern'; -import reactComponents from '../../_data/react-components'; -import spec from '../../_data/spec'; -import resource from '../../_data/resource'; -import config from '../website.config'; -import enLocale from './en-US.js'; -import cnLocale from './zh-CN.js'; -import { createHashHistory } from 'history'; - -// useRouterHistory creates a composable higher-order function -const appHistory = useRouterHistory(createHashHistory)({ queryKey: false }); - -// TODO: pack dependencies with atool build -// Expose React, ReactDOM -window.react = React; -window['react-dom'] = ReactDOM; -window.antd = antd; - -const ReactComponents = utils.generateContainer(reactComponents); -const Practice = utils.generateContainer(practice); -const Pattern = utils.generateContainer(pattern); -const Spec = utils.generateContainer(spec); -const Resource = utils.generateContainer(resource); -const redirects = Object.keys(config.redirects).map((from, index) => { - return ; -}); - -// Enable Google Analytics -if (!location.port) { - /* eslint-disable */ - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', 'UA-72788897-1', 'auto'); - ga('send', 'pageview'); - - appHistory.listen((loc) => { - ga('send', 'pageview', loc.pathname + loc.search); - }); - /* eslint-enable */ -} - -// Polyfill -const areIntlLocalesSupported = require('intl-locales-supported'); -const localesMyAppSupports = ['zh-CN', 'en-US']; - -if (global.Intl) { - // Determine if the built-in `Intl` has the locale data we need. - if (!areIntlLocalesSupported(localesMyAppSupports)) { - // `Intl` exists, but it doesn't have the data we need, so load the - // polyfill and patch the constructors we need with the polyfill's. - /* eslint-disable global-require */ - const IntlPolyfill = require('intl'); - /* eslint-enable global-require */ - Intl.NumberFormat = IntlPolyfill.NumberFormat; - Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat; - } -} else { - // No `Intl`, so use and load the polyfill. - /* eslint-disable global-require */ - global.Intl = require('intl'); - /* eslint-enable global-require */ -} - - -const isZhCN = (typeof localStorage !== 'undefined' && localStorage.getItem('locale') !== 'en-US'); - // (typeof localStorage !== 'undefined' && localStorage.getItem('locale') === 'zh-CN') || - // (navigator.language === 'zh-CN'); -const appLocale = isZhCN ? cnLocale : enLocale; -addLocaleData(appLocale.data); - -ReactDOM.render( - - - - - - {utils.generateIndex(reactComponents)} - - - {redirects} - - {utils.generateIndex(reactComponents)} - - - - {utils.generateIndex(practice)} - - - - {utils.generateIndex(pattern)} - - - - {utils.generateIndex(spec)} - - - - {utils.generateIndex(resource)} - - - - - - - , document.getElementById('react-content') -); diff --git a/site/entry/utils.js b/site/entry/utils.js deleted file mode 100644 index 808bb42d13..0000000000 --- a/site/entry/utils.js +++ /dev/null @@ -1,120 +0,0 @@ -/* eslint-disable react/prefer-stateless-function, react/no-multi-comp */ -import React from 'react'; -import { IndexRedirect } from 'react-router'; -import MainContent from '../component/MainContent'; -import Article from '../component/Article'; -import ComponentDoc from '../component/ComponentDoc'; -import demosList from '../../_data/demos-list'; -import { redirects } from '../website.config'; - -if (module.hot) { - module.hot.accept('../../_data/demos-list', () => {}); -} - -function fileNameToPath(fileName) { - const snippets = fileName - .replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '').split('/'); - return snippets[snippets.length - 1]; -} - -function getMenuItems(data, locale) { - const menuMeta = Object.keys(data) - .map((key) => data[key]) - .map((file) => { - if (file.localized) { - return file[locale].meta; - } - return file.meta; - }); - - const menuItems = {}; - menuMeta.sort((a, b) => { - return parseInt(a.order, 10) - parseInt(b.order, 10); - }).forEach((meta) => { - const category = meta.category || 'topLevel'; - if (!menuItems[category]) { - menuItems[category] = {}; - } - - const type = meta.type || 'topLevel'; - if (!menuItems[category][type]) { - menuItems[category][type] = []; - } - - menuItems[category][type].push(meta); - }); - - return menuItems; -} - -export function generateContainer(data) { - return class containerWrapper extends React.Component { - static contextTypes = { - intl: React.PropTypes.object, - } - - render() { - const locale = this.context.intl.locale; - const menuItems = getMenuItems(data, locale); - return ( - - ); - } - }; -} - -export function generateIndex(data) { - const menuItems = getMenuItems(data, 'zh-CN'); // 以中文版配置为准 - const firstChild = menuItems.topLevel.topLevel.filter((item) => { - return !item.disabled; - })[0]; - return ( - - ); -} - -const pathToFile = {}; -Object.keys(redirects).forEach((key) => pathToFile[redirects[key]] = key); -pathToFile['docs/react/changelog'] = './CHANGELOG'; // TODO - -function getDoc(data, props) { - const trimedPathname = props.location.pathname.replace(/^\//, ''); - const processedPathname = pathToFile[trimedPathname] || trimedPathname; - const doc = data[`${processedPathname}.md`] || - data[`${processedPathname}/index.md`]; - return doc; -} - -export function getChildrenWrapper(data) { - return class childrenWrapper extends React.Component { - static contextTypes = { - intl: React.PropTypes.object, - } - - render() { - const props = this.props; - const trimedPathname = props.location.pathname.replace(/^\//, ''); - const processedPathname = pathToFile[trimedPathname] || trimedPathname; - const rawDoc = data[`${processedPathname}.md`] || - data[`${processedPathname}/index.md`]; - - const locale = this.context.intl.locale; - const doc = rawDoc.localized ? rawDoc[locale] : rawDoc; - - const hasDemos = demosList[doc.meta.fileName.replace(`.${locale}`, '')]; - return !hasDemos ? -
: - ; - } - }; -} - -export function getEnterHandler(data) { - return function handleEnter(nextState, replace) { - const doc = getDoc(data, nextState); - if (!doc) { - replace('/404'); - } - }; -} diff --git a/site/common/styles/colors.less b/site/theme/static/colors.less similarity index 100% rename from site/common/styles/colors.less rename to site/theme/static/colors.less diff --git a/site/common/styles/mock-browser.less b/site/theme/static/mock-browser.less similarity index 100% rename from site/common/styles/mock-browser.less rename to site/theme/static/mock-browser.less diff --git a/site/common/styles/new-version-info-modal.less b/site/theme/static/new-version-info-modal.less similarity index 100% rename from site/common/styles/new-version-info-modal.less rename to site/theme/static/new-version-info-modal.less diff --git a/site/theme/static/style.js b/site/theme/static/style.js index ac0ff92303..60a6dd9c3b 100644 --- a/site/theme/static/style.js +++ b/site/theme/static/style.js @@ -12,3 +12,6 @@ import './not-found.less'; import './font.less'; import './highlight.less'; import './demo.less'; +import './colors.less'; +import './mock-browser.less'; +import './new-version-info-modal.less'; diff --git a/site/component/BrowserDemo/index.jsx b/site/theme/template/BrowserDemo.jsx similarity index 100% rename from site/component/BrowserDemo/index.jsx rename to site/theme/template/BrowserDemo.jsx diff --git a/site/theme/template/Content/ComponentDoc.jsx b/site/theme/template/Content/ComponentDoc.jsx index 334d4425de..6b93c65f80 100644 --- a/site/theme/template/Content/ComponentDoc.jsx +++ b/site/theme/template/Content/ComponentDoc.jsx @@ -110,7 +110,7 @@ export default class ComponentDoc extends React.Component { props.utils.toReactComponent( ['section', { className: 'markdown api-container', - }].concat(getChildren(doc.api || [])) + }].concat(getChildren(doc.api || ['placeholder'])) ) }
diff --git a/site/theme/template/Content/Demo.jsx b/site/theme/template/Content/Demo.jsx index d397d2debd..c2d7226a32 100644 --- a/site/theme/template/Content/Demo.jsx +++ b/site/theme/template/Content/Demo.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import classNames from 'classnames'; const isLocal = location.port; @@ -32,9 +33,9 @@ export default class Demo extends React.Component { const { meta, src, - preview, content, - code, + preview, + highlightedCode, style, highlightedStyle, } = props; @@ -61,7 +62,7 @@ export default class Demo extends React.Component { { meta.iframe ?