Commit 1b5902db authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

A more pragmatic solution for integrating sphinx in gui.

parent cb5e7475
Pipeline #37435 failed with stages
in 1 minute and 13 seconds
.build/
.static/
\ No newline at end of file
body {
font-family: "Roboto", "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif;
}
.wy-nav-top {
display: none
}
a {
color: #607D8B !important
}
a:visited {
color: #607D8B !important
}
\ No newline at end of file
......@@ -87,7 +87,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
......@@ -178,6 +178,7 @@ todo_include_todos = True
# Enably sphinx specifc markdown features
def setup(app):
app.add_stylesheet('css/custom.css')
app.add_config_value('recommonmark_config', {
'enable_auto_doc_ref': True,
'enable_eval_rst': True
......
.root {
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
color: rgba(0, 0, 0, 0.87);
font-size: 16px;
line-height: 1.6;
width: 1000px;
}
.root code {
font-family: "Roboto Mono", monospace;
}
.root .documentwrapper {
float: left;
width: 700px;
}
.root .sphinxsidebar {
padding: 0 20px;
margin-left: 730px;
}
.root .footer { display: none; }
.root #indices-and-tables { display: none; }
.root .relations { display: none; }
.root p {
-webkit-margin-before: 1em;
-webkit-margin-after: 1em;
-webkit-margin-start: 0px;
-webkit-margin-end: 0px;
}
.root h1 > a { display: none; }
.root h2 > a { display: none; }
.root h3 > a { display: none; }
.root h4 > a { display: none; }
.root a {
color: #607D8B;
}
.root h1 {
color: rgba(0, 0, 0, 0.54);
margin: 32px 0 24px;
font-size: 2.8125rem;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.13333em;
margin-left: -.02em;
}
.root h2 {
color: rgba(0, 0, 0, 0.54);
margin: 32px 0 24px;
font-size: 2.125rem;
font-weight: 400;
line-height: 1.20588em;
}
.root h3 {
color: rgba(0, 0, 0, 0.87);
margin: 24px 0 18px;
font-size: 1.5rem;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.35417em;
}
.root h4 {
color: rgba(0, 0, 0, 0.87);
margin: 18px 0 12px;
font-size: 1rem;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.5em;
}
.root pre {
margin: 24px 0;
padding: 12px 18px;
overflow: auto;
border-radius: 4px;
background-color: #fff;
}
.root ul {
margin: 0;
padding: 0;
list-style: none;
padding-bottom: 12px;
}
.root li:first-child {
padding-top: 12px;
}
.root li {
padding-bottom: 8px;
width: 100%;
text-align: left;
align-items: center;
padding-left: 12px;
text-decoration: none;
}
.root img {
width: 700px;
}
.root .caption {
text-align: center;
color: rgba(0, 0, 0, 0.54);
font-size: 14px;
font-weight: 400;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
line-height: 1.375;
}
.root div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
.root div.admonition dt {
font-weight: bold;
}
.root div.admonition dl {
margin-bottom: 0;
}
.root p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
.root div.body p.centered {
text-align: center;
margin-top: 25px;
}
.root dd p {
margin-top: 0;
}
.root .field-body strong {
font-family: "Roboto Mono", monospace;
}
.root .descname {
font-weight: 500;
}
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import HtmlToReact from 'html-to-react'
import { withRouter } from 'react-router-dom'
import { HashLink as Link } from 'react-router-hash-link'
import './Documentation.css'
import Url from 'url-parse'
import { apiBase, appBase } from '../config'
import { withStyles } from '@material-ui/core';
const docBaseRegExp = new RegExp(`^(${appBase.replace('/', '\\/')})?(\\/docs/)?`)
const processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React)
const processingInstructions = location => {
return [
{
// We have to remove sphynx header links. Not all of them are cought with css.
shouldProcessNode: node => node.name === 'a' && node.children[0].data === '',
processNode: (node, children) => {
return ''
}
},
{
// We have to replace the sphynx links with router Links;
// the hrefs have to be processed to be compatible with router, i.e. they have
// to start with /documentation/.
shouldProcessNode: node => node.type === 'tag' && node.name === 'a' && node.attribs['href'] && !node.attribs['href'].startsWith('http'),
processNode: function DocLink(node, children) {
const linkUrl = Url(node.attribs['href'])
let pathname = linkUrl.pathname.replace(docBaseRegExp, '').replace(/^\//, '')
if (pathname === '') {
pathname = location.pathname
} else {
pathname = `/docs/${pathname}`
}
return (
<Link smooth to={pathname + (linkUrl.hash || '#')}>{children}</Link>
)
}
},
{
// We have to redirect img src attributes to the static sphynx build dir.
shouldProcessNode: node => node.type === 'tag' && node.name === 'img' && node.attribs['src'] && !node.attribs['src'].startsWith('http'),
processNode: (node, children) => {
node.attribs['src'] = `${apiBase}/docs/${node.attribs['src']}`
return processNodeDefinitions.processDefaultNode(node)
}
},
{
shouldProcessNode: node => true,
processNode: processNodeDefinitions.processDefaultNode
}
]
}
const isValidNode = () => true
const htmlToReactParser = new HtmlToReact.Parser()
const domParser = new DOMParser() // eslint-disable-line no-undef
class Documentation extends Component {
static propTypes = {
location: {
pathname: PropTypes.string.isRequired
}
classes: PropTypes.object.isRequired,
}
state = {
react: ''
}
onRouteChanged() {
const fetchAndUpdate = path => {
if (path === '' || path.startsWith('#')) {
path = '/index.html' + path
}
fetch(`${apiBase}/docs${path}`)
.then(response => response.text())
.then(content => {
// extract body of html page
const doc = domParser.parseFromString(content, 'application/xml')
const bodyHtml = doc.getElementsByTagName('body')[0].innerHTML
// replace a hrefs with Link to
const react = htmlToReactParser.parseWithInstructions(bodyHtml, isValidNode, processingInstructions(this.props.location))
this.setState({
react: react
})
})
.catch(err => {
if (path !== 'index.html') {
fetchAndUpdate('index.html')
} else {
console.error(err)
}
})
}
const path = this.props.location.pathname.replace(`/docs`, '')
fetchAndUpdate(path)
}
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
this.onRouteChanged()
static styles = theme => ({
root: {
position: 'relative',
},
content: {
position: 'absolute',
left: -theme.spacing.unit * 3,
top: -theme.spacing.unit * 3
}
}
componentDidMount() {
this.onRouteChanged()
}
})
render() {
const {classes} = this.props
return (
<div className="root">
{this.state.react}
<div className={classes.root}>
<div className={classes.content}>
<iframe
frameBorder={0} width="768" height={window.innerHeight - 64}
src="http://localhost:8000/nomad/api/docs/index.html"
/>
</div>
</div>
)
}
}
export default withRouter(Documentation)
export default withStyles(Documentation.styles)(Documentation)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment