Initial release
This commit is contained in:
commit
cb9f39566a
110 changed files with 17144 additions and 0 deletions
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
build
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
.*.swp
|
||||||
|
ui/node_modules
|
||||||
|
ui/dist
|
||||||
|
dist
|
||||||
|
demo/_build
|
||||||
|
sphinx_nervproject_theme.egg-info
|
||||||
|
|
4
AUTHORS
Normal file
4
AUTHORS
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(in chronological order)
|
||||||
|
|
||||||
|
* Eduardo Schettino - schettino72 <at> gmail <dot> com
|
||||||
|
* Zulko @ Github
|
43
CHANGES
Normal file
43
CHANGES
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
=======
|
||||||
|
Changes
|
||||||
|
=======
|
||||||
|
|
||||||
|
0.5.0 (*2019-10-01*)
|
||||||
|
=====================
|
||||||
|
|
||||||
|
- new CSS styles to handle Sphinx-specific classes (fixes #26)
|
||||||
|
- add support for user-provided CSS stylesheets (fixes #25)
|
||||||
|
- allow support for user-defined external links
|
||||||
|
|
||||||
|
0.4.0 (*2019-05-27*)
|
||||||
|
====================
|
||||||
|
|
||||||
|
- fix reading cached toctree data
|
||||||
|
- fix navlinks that contain `#` anchors
|
||||||
|
|
||||||
|
|
||||||
|
0.3.0 (*2019-04-22*)
|
||||||
|
====================
|
||||||
|
|
||||||
|
- require Sphinx >= 2.0
|
||||||
|
- inherit from `basic` theme (previously `none`)
|
||||||
|
- support search
|
||||||
|
- support showing logo
|
||||||
|
- add breadcrumbs
|
||||||
|
- add page navigation on page top
|
||||||
|
- fix #12: load extensions JS files
|
||||||
|
- fix #10: don't raise error if there is no toctree
|
||||||
|
- no navlinks to toctree if there is only one toctree defined
|
||||||
|
|
||||||
|
|
||||||
|
0.2.0 (*2019-03-19*)
|
||||||
|
====================
|
||||||
|
|
||||||
|
- added template domainindex.html
|
||||||
|
|
||||||
|
|
||||||
|
0.1.0 (*2018-08-07*)
|
||||||
|
====================
|
||||||
|
|
||||||
|
- initial release
|
||||||
|
|
49
README.md
Normal file
49
README.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# sphinx_nervproject_theme
|
||||||
|
|
||||||
|
A modern responsive theme for python's [Sphinx](http://www.sphinx-doc.org) documentation generator based on
|
||||||
|
sphinx_press_theme.
|
||||||
|
|
||||||
|
This theme is based on [VuePress](https://vuepress.vuejs.org/).
|
||||||
|
It uses [Vue.js](https://vuejs.org/) & [Stylus](http://stylus-lang.com/) managed by
|
||||||
|
[webpack](https://webpack.js.org/) (through [vue-cli](https://cli.vuejs.org/)).
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
|
||||||
|
On Sphinx project's ``conf.py``: set the theme name to ``nervproject``.
|
||||||
|
|
||||||
|
```
|
||||||
|
html_theme = "nervproject"
|
||||||
|
```
|
||||||
|
|
||||||
|
See details on [Sphinx theming docs](http://www.sphinx-doc.org/en/master/theming.html#using-a-theme).
|
||||||
|
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
First build web assets:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd ui
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Sphinx theme has a soft link to built assets...
|
||||||
|
Install theme locally with `pip install -e .`.
|
||||||
|
|
||||||
|
`docs` folder contains theme's own documentantion.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd docs
|
||||||
|
make clean; make html
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Website
|
||||||
|
|
||||||
|
To update website:
|
||||||
|
|
||||||
|
cd ../press_site
|
||||||
|
rsync -rvi ../sphinx_vuepress_theme/docs/build/html/ .
|
||||||
|
git add --all
|
19
demo/Makefile
Normal file
19
demo/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
59
demo/conf.py
Normal file
59
demo/conf.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# http://www.sphinx-doc.org/en/master/config
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = 'demo'
|
||||||
|
copyright = '2019, Eduardo'
|
||||||
|
author = 'Eduardo'
|
||||||
|
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = '0.1'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
master_doc = 'source/index'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.mathjax',
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'nervproject'
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
35
demo/make.bat
Normal file
35
demo/make.bat
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
|
set BUILDDIR=_build
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.http://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
1
demo/source/README
Normal file
1
demo/source/README
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Demo pages taken from https://github.com/sphinx-themes/sphinx-themes.org
|
68
demo/source/admonition.rst
Normal file
68
demo/source/admonition.rst
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
Admonitions
|
||||||
|
===============
|
||||||
|
|
||||||
|
admonition
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. admonition:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
|
||||||
|
caution
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. caution:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
danger
|
||||||
|
---------------
|
||||||
|
|
||||||
|
|
||||||
|
.. danger:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
error
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. error:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
|
||||||
|
hint
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. hint:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
important
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. important:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
note
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. note:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
tip
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. tip:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
||||||
|
|
||||||
|
warning
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. warning:: Neque porro quisquam
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mattis commodo eros, quis posuere enim lobortis quis. Nullam ut tempus nibh.
|
115
demo/source/basic.rst
Normal file
115
demo/source/basic.rst
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
Basic Specification
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Paragraphs contain text and may contain inline markup: *emphasis*, **strong emphasis**, `interpreted text`, ``inline literals``, standalone hyperlinks (http://www.python.org), external hyperlinks (Python_), internal cross-references (example_), footnote references ([1]_), citation references ([CIT2002]_), substitution references (|example|), and _`inline internal targets`.
|
||||||
|
|
||||||
|
|
||||||
|
Table of contents
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
.. |example| replace:: foo **bar**
|
||||||
|
|
||||||
|
|
||||||
|
List
|
||||||
|
----
|
||||||
|
|
||||||
|
Bullet lists:
|
||||||
|
```````````````
|
||||||
|
|
||||||
|
- This is a bullet list.
|
||||||
|
|
||||||
|
- Bullets can be "*", "+", or "-".
|
||||||
|
|
||||||
|
|
||||||
|
Enumerated lists:
|
||||||
|
``````````````````
|
||||||
|
|
||||||
|
1. This is an enumerated list.
|
||||||
|
|
||||||
|
2. Enumerators may be arabic numbers, letters, or roman
|
||||||
|
numerals.
|
||||||
|
|
||||||
|
Definition lists:
|
||||||
|
``````````````````
|
||||||
|
|
||||||
|
what
|
||||||
|
Definition lists associate a term with a definition.
|
||||||
|
|
||||||
|
how
|
||||||
|
The term is a one-line phrase, and the definition is one
|
||||||
|
or more paragraphs or body elements, indented relative to
|
||||||
|
the term.
|
||||||
|
|
||||||
|
Field lists:
|
||||||
|
````````````
|
||||||
|
|
||||||
|
:what: Field lists map field names to field bodies, like
|
||||||
|
database records. They are often part of an extension
|
||||||
|
syntax.
|
||||||
|
|
||||||
|
:how: The field marker is a colon, the field name, and a
|
||||||
|
colon.
|
||||||
|
|
||||||
|
The field body may contain one or more body elements,
|
||||||
|
indented relative to the field marker.
|
||||||
|
|
||||||
|
Option lists, for listing command-line options:
|
||||||
|
``````````````````````````````````````````````````````````
|
||||||
|
|
||||||
|
-a command-line option "a"
|
||||||
|
-b file options can have arguments
|
||||||
|
and long descriptions
|
||||||
|
--long options can be long also
|
||||||
|
--input=file long options can also have
|
||||||
|
arguments
|
||||||
|
/V DOS/VMS-style options too
|
||||||
|
|
||||||
|
|
||||||
|
Literal blocks:
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
if literal_block:
|
||||||
|
text = 'is left as-is'
|
||||||
|
spaces_and_linebreaks = 'are preserved'
|
||||||
|
markup_processing = None
|
||||||
|
|
||||||
|
|
||||||
|
Block quotes:
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This theory, that is mine, is mine.
|
||||||
|
|
||||||
|
-- Anne Elk (Miss)
|
||||||
|
|
||||||
|
|
||||||
|
Simple Table
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
==================== ========== ==========
|
||||||
|
Header row, column 1 Header 2 Header 3
|
||||||
|
==================== ========== ==========
|
||||||
|
body row 1, column 1 column 2 column 3
|
||||||
|
body row 2 Cells may span columns
|
||||||
|
==================== ======================
|
||||||
|
|
||||||
|
Citation
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. [1] A footnote contains body elements, consistently
|
||||||
|
indented by at least 3 spaces.
|
||||||
|
|
||||||
|
.. [CIT2002] Just like a footnote, except the label is
|
||||||
|
textual.
|
||||||
|
|
||||||
|
|
||||||
|
Internal reference
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. _example:
|
||||||
|
|
||||||
|
The "_example" target above points to this paragraph.
|
||||||
|
|
||||||
|
|
||||||
|
.. _Python: http://www.python.org
|
25
demo/source/domain.rst
Normal file
25
demo/source/domain.rst
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Domain
|
||||||
|
======
|
||||||
|
|
||||||
|
|
||||||
|
Python
|
||||||
|
------
|
||||||
|
|
||||||
|
.. py:module:: foo
|
||||||
|
|
||||||
|
|
||||||
|
.. py:function:: spam(eggs)
|
||||||
|
|
||||||
|
My spam
|
||||||
|
|
||||||
|
autofunction
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. autofunction:: sphinx_press_theme.add_toctree_data
|
||||||
|
|
||||||
|
autoclass
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. autoclass:: sphinx.environment.collectors.EnvironmentCollector
|
||||||
|
:members:
|
||||||
|
|
11
demo/source/extensions.rst
Normal file
11
demo/source/extensions.rst
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
Extensions
|
||||||
|
==========
|
||||||
|
|
||||||
|
mathjax
|
||||||
|
-------
|
||||||
|
|
||||||
|
|
||||||
|
Inline :math:`\hat{y}` or:
|
||||||
|
|
||||||
|
.. math:: \hat{y} = f(x) = wx
|
13
demo/source/index.rst
Normal file
13
demo/source/index.rst
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Demo
|
||||||
|
====
|
||||||
|
|
||||||
|
Showcase of Sphinx features using **Press** theme.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
basic
|
||||||
|
admonition
|
||||||
|
domain
|
||||||
|
extensions
|
||||||
|
|
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
SPHINXPROJ = sphinx_press_theme
|
||||||
|
SOURCEDIR = source
|
||||||
|
BUILDDIR = build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
36
docs/make.bat
Normal file
36
docs/make.bat
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=source
|
||||||
|
set BUILDDIR=build
|
||||||
|
set SPHINXPROJ=sphinx_press_theme
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.http://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
6
docs/source/_templates/util/extlinks.html
Normal file
6
docs/source/_templates/util/extlinks.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="https://github.com/schettino72/sphinx_press_theme"
|
||||||
|
class="nav-link external">
|
||||||
|
Github <outboundlink/>
|
||||||
|
</a>
|
||||||
|
</div>
|
42
docs/source/about.rst
Normal file
42
docs/source/about.rst
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
=====
|
||||||
|
About
|
||||||
|
=====
|
||||||
|
|
||||||
|
Sphinx Press is a modern responsive theme for python's
|
||||||
|
`Sphinx docs <http://www.sphinx-doc.org>`_.
|
||||||
|
|
||||||
|
This theme is based on `VuePress <https://vuepress.vuejs.org/>`_.
|
||||||
|
It uses `Vue.js <https://vuejs.org/>`_ &
|
||||||
|
`Stylus <http://stylus-lang.com/>`_ managed by
|
||||||
|
`webpack <https://webpack.js.org/>`_
|
||||||
|
(through `vue-cli <https://cli.vuejs.org/>`_).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
|
||||||
|
First install the theme:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ pip install sphinx_press_theme
|
||||||
|
|
||||||
|
|
||||||
|
On Sphinx project's ``conf.py``: set the theme name to ``press``.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
html_theme = "press"
|
||||||
|
|
||||||
|
|
||||||
|
See details on `Sphinx theming docs <http://www.sphinx-doc.org/en/master/theming.html#using-a-theme>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Status
|
||||||
|
======
|
||||||
|
|
||||||
|
**Press** theme is still in **BETA**.
|
||||||
|
|
||||||
|
Contributions are welcome.
|
1
docs/source/changes.rst
Symbolic link
1
docs/source/changes.rst
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../CHANGES
|
163
docs/source/conf.py
Normal file
163
docs/source/conf.py
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file does only contain a selection of the most common options. For a
|
||||||
|
# full list see the documentation:
|
||||||
|
# http://www.sphinx-doc.org/en/master/config
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = 'sphinx_press_theme'
|
||||||
|
copyright = '2018, Eduardo Naufel Schettino'
|
||||||
|
author = 'Eduardo Naufel Schettino'
|
||||||
|
|
||||||
|
# The short X.Y version
|
||||||
|
version = ''
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = '0.5.1'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
#
|
||||||
|
needs_sphinx = '2.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.mathjax',
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
# 'sphinx.ext.ifconfig',
|
||||||
|
# 'sphinx.ext.viewcode',
|
||||||
|
# 'sphinx.ext.githubpages',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
#
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
|
source_suffix = '.rst'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path .
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = None
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'press'
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# documentation.
|
||||||
|
#
|
||||||
|
# html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Custom sidebar templates, must be a dictionary that maps document names
|
||||||
|
# to template names.
|
||||||
|
#
|
||||||
|
# The default sidebars (for documents that don't match any pattern) are
|
||||||
|
# defined by theme itself.
|
||||||
|
#
|
||||||
|
# The default `html_sidebars` of Press theme: ['util/searchbox.html', 'util/sidetoc.html']
|
||||||
|
#
|
||||||
|
# html_sidebars = {'**': ['util/sidetoc.html']}
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTMLHelp output ---------------------------------------------
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'sphinx_press_themedoc'
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ------------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#
|
||||||
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#
|
||||||
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#
|
||||||
|
# 'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#
|
||||||
|
# 'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(master_doc, 'sphinx_press_theme.tex', 'sphinx\\_press\\_theme Documentation',
|
||||||
|
'Eduardo Naufel Schettino', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ------------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(master_doc, 'sphinx_press_theme', 'sphinx_press_theme Documentation',
|
||||||
|
[author], 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output ----------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'sphinx_press_theme', 'sphinx_press_theme Documentation',
|
||||||
|
author, 'sphinx_press_theme', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# -- Extension configuration -------------------------------------------------
|
145
docs/source/configuration.rst
Normal file
145
docs/source/configuration.rst
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
=============
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
The Press theme webpage is composed of a fixed header, a sidebar and main content area.
|
||||||
|
|
||||||
|
The ``util`` folder contains Jinja2 snippets to be *included*,
|
||||||
|
from main templates. Those can be easily replaced by theme users.
|
||||||
|
|
||||||
|
To change site/page structure you should *extend* pages and give new implementations for Jinja2 **blocks**.
|
||||||
|
|
||||||
|
Jinja2 templates and blocks are organized as follow:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Config values
|
||||||
|
=============
|
||||||
|
|
||||||
|
``html_logo``
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If defined shows an image instead of project name on page top-left (link to index page).
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
html_logo = '_static/myproject-logo.png'
|
||||||
|
|
||||||
|
|
||||||
|
``html_sidebars``
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
By default the *sidebars* include only: searchbox and a global TOC tree.
|
||||||
|
See docs on `html_sidebars <http://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_sidebars>`_.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
html_sidebars = {'**': ['util/searchbox.html', 'util/sidetoc.html']}
|
||||||
|
|
||||||
|
|
||||||
|
``html_css_files``
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Adds custom CSS files to the theme
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Here we assume that the file is at _static/css/custom.css
|
||||||
|
html_css_files = ["css/custom.css"]
|
||||||
|
|
||||||
|
``html_external_links``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
If provided, creates external links (e.g. Github) in the top right corner:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
html_theme_options = {
|
||||||
|
"external_links": [
|
||||||
|
("Github", "https://github.com/username/repo"),
|
||||||
|
("Other", "https://bla.com")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Templates
|
||||||
|
=========
|
||||||
|
|
||||||
|
|
||||||
|
``layout.html``
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Blocks on HTML head:
|
||||||
|
|
||||||
|
- ``htmltitle`` - HTML page title
|
||||||
|
- ``css`` - include theme's CSS files
|
||||||
|
- ``scripts`` - include theme's javascript files
|
||||||
|
- ``extrahead`` - empty by default, to be used by theme users
|
||||||
|
|
||||||
|
|
||||||
|
Blocks on HTML body:
|
||||||
|
|
||||||
|
``container`` - whole visible page
|
||||||
|
|
||||||
|
* ``header`` - fixed header (includes ``util/navbar.html``)
|
||||||
|
|
||||||
|
- ``navbar.html`` - apart from home-link includes ``util/navlinks.html`` & ``util/extlinks.html``
|
||||||
|
|
||||||
|
* ``sidebar``
|
||||||
|
|
||||||
|
- ``side_links`` - includes ``util/navlinks.html`` & ``util/extlinks.html``
|
||||||
|
- include all templates listed on ``html_sidebars`` config
|
||||||
|
|
||||||
|
* ``document``
|
||||||
|
|
||||||
|
- ``body_header`` - includes ``util/bodyheader.html``
|
||||||
|
- ``body`` - main content generated from ReST documents
|
||||||
|
- ``footer`` - includes ``util/pagenav.html`` & ``util/footer.html``
|
||||||
|
|
||||||
|
|
||||||
|
``util/navbar.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Header content. Left side contains *home-link* with name.
|
||||||
|
|
||||||
|
Right side contains links from ``util/navlinks.html`` and ``util/extlinks.html``.
|
||||||
|
|
||||||
|
|
||||||
|
``util/navlinks.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Links taken from TOCs defined on master document.
|
||||||
|
|
||||||
|
|
||||||
|
``util/extlinks.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
External links defined by theme's user.
|
||||||
|
|
||||||
|
|
||||||
|
``util/searchbox.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Form to perform site search.
|
||||||
|
|
||||||
|
``util/sidetoc.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Navigation from toctree.
|
||||||
|
|
||||||
|
|
||||||
|
``util/bodyheader.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Breadcrumbs and page navigation.
|
||||||
|
|
||||||
|
``util/pagenav.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Links for previous/next page.
|
||||||
|
|
||||||
|
|
||||||
|
``util/footer.html``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Copyright information.
|
||||||
|
|
31
docs/source/index.rst
Normal file
31
docs/source/index.rst
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
.. sphinx_press_theme documentation master file, created by
|
||||||
|
sphinx-quickstart on Mon Jul 30 11:44:38 2018.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
sphinx_press_theme
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Docs
|
||||||
|
|
||||||
|
about
|
||||||
|
configuration
|
||||||
|
who
|
||||||
|
changes
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Demo
|
||||||
|
|
||||||
|
theme-demo/index
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
1
docs/source/theme-demo
Symbolic link
1
docs/source/theme-demo
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../demo/source
|
14
docs/source/who.rst
Normal file
14
docs/source/who.rst
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Who is using **Press** Theme
|
||||||
|
============================
|
||||||
|
|
||||||
|
If you this theme please add your site below:
|
||||||
|
|
||||||
|
|
||||||
|
- `doit <https://pydoit.org>`_
|
||||||
|
- `Crudcast <https://crudcast.readthedocs.io/en/latest/>`_
|
||||||
|
- `Friendly ML Tutorial <https://aunnnn.github.io/ml-tutorial/html/index.html>`_
|
||||||
|
- `Kube Control <https://ktl.leftxs.org/>`_
|
||||||
|
- `Butter MAS Python API <https://bennymeg.github.io/Butter.MAS.PythonAPI/>`_
|
||||||
|
- `trcls <https://trcls.ningyuan.io>`_
|
||||||
|
- `bedshape <https://bedshape.ningyuan.io>`_
|
||||||
|
- `DNA Chisel <https://edinburgh-genome-foundry.github.io/DnaChisel/>`_
|
51
setup.py
Normal file
51
setup.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="sphinx_nervproject_theme",
|
||||||
|
version="0.5.1",
|
||||||
|
url="https://schettino72.github.io/sphinx_press_site/",
|
||||||
|
license="MIT",
|
||||||
|
author="Eduardo Naufel Schettino <schetino72>",
|
||||||
|
description="A Sphinx-doc theme based on Vuepress",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
packages=["sphinx_nervproject_theme"],
|
||||||
|
package_data={
|
||||||
|
"sphinx_nervproject_theme": [
|
||||||
|
"theme.conf",
|
||||||
|
"*.html",
|
||||||
|
"util/*.html",
|
||||||
|
"ablog/*.html",
|
||||||
|
"static/*.css",
|
||||||
|
"static/*.js",
|
||||||
|
"static/fonts/luciole/*.ttf",
|
||||||
|
"static/fonts/hack/*.ttf",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
entry_points={"sphinx.html_themes": ["nervproject = sphinx_nervproject_theme"]},
|
||||||
|
install_requires=["sphinx>=2.0.0"],
|
||||||
|
classifiers=[
|
||||||
|
"Framework :: Sphinx",
|
||||||
|
"Framework :: Sphinx :: Theme",
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Environment :: Console",
|
||||||
|
"Environment :: Web Environment",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.5",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Topic :: Documentation",
|
||||||
|
"Topic :: Software Development :: Documentation",
|
||||||
|
],
|
||||||
|
keywords="sphinx doc theme vue.js",
|
||||||
|
project_urls={
|
||||||
|
"Source": "https://procrastinator.nerv-project.eu/nerv-project/communication/sphinx_nervproject_theme",
|
||||||
|
"Issues": "https://procrastinator.nerv-project.eu/nerv-project/communication/sphinx_nervproject_theme/issues",
|
||||||
|
},
|
||||||
|
)
|
164
sphinx_nervproject_theme/__init__.py
Normal file
164
sphinx_nervproject_theme/__init__.py
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from sphinx.environment.collectors import EnvironmentCollector
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.util.osutil import relative_uri
|
||||||
|
|
||||||
|
__version__ = (0, 4, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleTocTreeCollector(EnvironmentCollector):
|
||||||
|
"""A TocTree collector that saves toctrees in a simple dict.
|
||||||
|
|
||||||
|
sphinx.environment.collectors.toctree.TocTreeCollector saves
|
||||||
|
TocTree as docutils.nodes which are hard to work with...
|
||||||
|
|
||||||
|
Executed once per document/page, at sphinx's "read" phase.
|
||||||
|
|
||||||
|
Saved data example:
|
||||||
|
>>> {
|
||||||
|
>>> 'sections': [{'title': 'Demo', 'href': '#demo'}],
|
||||||
|
>>> 'toctrees': [<toctree: >]
|
||||||
|
>>> }
|
||||||
|
"""
|
||||||
|
def enable(self, app):
|
||||||
|
super().enable(app)
|
||||||
|
# env is populated from cache, if not cache create/initalize attibute
|
||||||
|
if not hasattr(app.env, 'toc_dict'):
|
||||||
|
app.env.toc_dict = {}
|
||||||
|
|
||||||
|
def clear_doc(self, app, env, docname):
|
||||||
|
env.toc_dict.pop(docname, None)
|
||||||
|
|
||||||
|
def merge_other(self, app, env, docnames, other):
|
||||||
|
for docname in docnames:
|
||||||
|
env.toc_dict[docname] = other.toc_dict[docname]
|
||||||
|
|
||||||
|
|
||||||
|
def process_doc(self, app, doctree):
|
||||||
|
docname = app.env.docname # sphinx mutates this, ouch!!!
|
||||||
|
|
||||||
|
# print(f"================ Collector\n{docname}\n============\n")
|
||||||
|
# get 1 level document toc (sections)
|
||||||
|
section_nodes = [s for s in doctree if isinstance(s, nodes.section)]
|
||||||
|
# if first level is a single section,
|
||||||
|
# ignore it and use second level of sections
|
||||||
|
if len(section_nodes) == 1:
|
||||||
|
section2_nodes = [s for s in section_nodes[0]
|
||||||
|
if isinstance(s, nodes.section)]
|
||||||
|
if section2_nodes: # do not replace with level-2 sections if None
|
||||||
|
section_nodes = section2_nodes
|
||||||
|
|
||||||
|
sections = []
|
||||||
|
for node in section_nodes:
|
||||||
|
sections.append({
|
||||||
|
'title': node[0].astext(),
|
||||||
|
'href': '#{}'.format(node['ids'][0]),
|
||||||
|
})
|
||||||
|
|
||||||
|
app.env.toc_dict[docname] = {
|
||||||
|
'sections': sections,
|
||||||
|
'toctrees': doctree.traverse(addnodes.toctree)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def add_toctree_data(app, pagename, templatename, context, doctree):
|
||||||
|
"""Create toctree_data, used to build sidebar navigation
|
||||||
|
|
||||||
|
:param pagename: The name of the page
|
||||||
|
:type pagename: str
|
||||||
|
:param templatename: The name of the templatename
|
||||||
|
:type templatename: str
|
||||||
|
:param context: The context
|
||||||
|
:type context: dict
|
||||||
|
:param doctree: A doctree
|
||||||
|
:type doctree: docutils.nodes.document
|
||||||
|
|
||||||
|
Add to `toctree_data` to `context` that will be available on templates.
|
||||||
|
Although data is "global", it is called once per page because current
|
||||||
|
page is "highlighted", and some part of TOC might be collapsed.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# print(f"---------- Context\n{pagename}\n-------------\n")
|
||||||
|
|
||||||
|
# start from master_doc
|
||||||
|
master = app.env.get_doctree(app.env.config.master_doc)
|
||||||
|
|
||||||
|
# each toctree will create navigation section
|
||||||
|
res = [] # list of top level toctrees in master_doc
|
||||||
|
for tree in master.traverse(addnodes.toctree):
|
||||||
|
|
||||||
|
# special case for toctree that includes a single item
|
||||||
|
# that contains a nested toctree.
|
||||||
|
# In this case, just use the referenced toctree directly
|
||||||
|
if len(tree['entries']) == 1:
|
||||||
|
entry_docname = tree['entries'][0][1]
|
||||||
|
toctrees = app.env.toc_dict[entry_docname]['toctrees']
|
||||||
|
|
||||||
|
if toctrees:
|
||||||
|
# FIXME
|
||||||
|
assert len(toctrees) == 1, "Press: Not supported more then one toctree on nested toctree"
|
||||||
|
tree = toctrees[0]
|
||||||
|
|
||||||
|
current0 = False # same page might have multiple tocs
|
||||||
|
|
||||||
|
# add toc tree items, expand one more level if toctree is current page
|
||||||
|
entries = []
|
||||||
|
for title, name in tree['entries']:
|
||||||
|
if not title:
|
||||||
|
title = app.env.titles[name].astext()
|
||||||
|
|
||||||
|
current1 = (pagename == name)
|
||||||
|
children = []
|
||||||
|
if current1:
|
||||||
|
current0 = True
|
||||||
|
# if current, add another level
|
||||||
|
children = app.env.toc_dict[name]['sections']
|
||||||
|
# add page_toc for current page
|
||||||
|
entries.append({
|
||||||
|
'name': name,
|
||||||
|
'title': title,
|
||||||
|
'current': current1,
|
||||||
|
'children': children,
|
||||||
|
})
|
||||||
|
|
||||||
|
toc_docname = tree['parent'] # docname where this toc appears
|
||||||
|
title = tree['caption']
|
||||||
|
|
||||||
|
# Anchor element is the section containing the toc,
|
||||||
|
# as the toc itself does not contain ID.
|
||||||
|
anchor_id = ''
|
||||||
|
|
||||||
|
# tree.parent is the parent docutils node.
|
||||||
|
# First parent is "compound" node toctree-wrapper,
|
||||||
|
# second parent is the section containing the toctree
|
||||||
|
toc_section = tree.parent.parent
|
||||||
|
if toc_section['ids']: # no id means toc actually not in a section
|
||||||
|
# TODO: should we be strict about toc being inside a section
|
||||||
|
anchor_id = toc_section['ids'][0]
|
||||||
|
if not title:
|
||||||
|
title = toc_section['names'][0]
|
||||||
|
|
||||||
|
# sphinx `pathto` does not play nice with anchors when
|
||||||
|
# `allow_sharp_as_current_path` is True
|
||||||
|
baseuri = app.builder.get_target_uri(pagename).rsplit('#', 1)[0]
|
||||||
|
toc_uri = app.builder.get_target_uri(toc_docname).rsplit('#', 1)[0]
|
||||||
|
toc_href = '{}#{}'.format(relative_uri(baseuri, toc_uri), anchor_id)
|
||||||
|
res.append({
|
||||||
|
'docname': toc_docname,
|
||||||
|
'href': toc_href,
|
||||||
|
'title': title,
|
||||||
|
'current': current0,
|
||||||
|
'entries': entries,
|
||||||
|
})
|
||||||
|
context['toctree_data'] = res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_env_collector(SimpleTocTreeCollector)
|
||||||
|
app.connect('html-page-context', add_toctree_data)
|
||||||
|
app.add_html_theme('nervproject', path.abspath(path.dirname(__file__)))
|
13
sphinx_nervproject_theme/ablog/archives.html
Normal file
13
sphinx_nervproject_theme/ablog/archives.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% if ablog.archive %}
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="archive">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<h3><a href="{{ pathto(ablog.archive.docname) }}">{{ gettext('Archives') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% for coll in ablog.archive %}
|
||||||
|
{% if coll %}
|
||||||
|
<li><a href="{{ pathto(coll.docname) }}">{{ coll }} ({{ coll|length }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
10
sphinx_nervproject_theme/ablog/authors.html
Normal file
10
sphinx_nervproject_theme/ablog/authors.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% if ablog.author %}
|
||||||
|
<h3><a href="{{ pathto(ablog.author.path) }}">{{ gettext('Authors') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% for coll in ablog.author %}
|
||||||
|
{% if coll %}
|
||||||
|
<li><a href="{{ pathto(coll.docname) }}">{{ coll }} ({{ coll|length }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
28
sphinx_nervproject_theme/ablog/catalog.html
Normal file
28
sphinx_nervproject_theme/ablog/catalog.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{%- extends "page.html" %}
|
||||||
|
{% block body %}
|
||||||
|
{% for collection in catalog %}
|
||||||
|
{% if collection %}
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
{{ header }}
|
||||||
|
<a href="{{ pathto(collection.docname) }}">{{ collection }}</a>
|
||||||
|
</h2>
|
||||||
|
{% for post in collection %}
|
||||||
|
<div class="section">
|
||||||
|
<p>
|
||||||
|
{% if fa %}{% endif %}
|
||||||
|
{% if post.published %}
|
||||||
|
{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %}
|
||||||
|
Draft
|
||||||
|
{% endif %}
|
||||||
|
- <a href="{{ pathto(post.docname) }}{{ anchor(post) }}">{{ post.title }}</a>
|
||||||
|
</p>
|
||||||
|
{% if 0 %}<ul class="ablog-archive">{% include "postcard2.html" %}</ul>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
13
sphinx_nervproject_theme/ablog/categories.html
Normal file
13
sphinx_nervproject_theme/ablog/categories.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% if ablog.category %}
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="categories">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<h3><a href="{{ pathto(ablog.category.path) }}">{{ gettext('Categories') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% for coll in ablog.category %}
|
||||||
|
{% if coll %}
|
||||||
|
<li><a href="{{ pathto(coll.docname) }}">{{ coll }} ({{ coll|length }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
54
sphinx_nervproject_theme/ablog/collection.html
Normal file
54
sphinx_nervproject_theme/ablog/collection.html
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{%- extends "page.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="section">
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
{% if archive_feed and fa %}
|
||||||
|
<a href="{{ pathto(collection.path, 1) }}/atom.xml"><i class="fa fa-rss fa-rotate-270"></i></a>{% endif %}
|
||||||
|
{{ header }}
|
||||||
|
{% if collection.href %}
|
||||||
|
<a href="{{ collection.href }}">{{ collection }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ collection }}
|
||||||
|
{% endif %}
|
||||||
|
</h1>
|
||||||
|
{% if ablog.blog_archive_titles %}
|
||||||
|
{% for post in collection %}
|
||||||
|
<div class="section">
|
||||||
|
<p>
|
||||||
|
{% if fa %}{% endif %}
|
||||||
|
{% if post.published %}
|
||||||
|
{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %}
|
||||||
|
Draft
|
||||||
|
{% endif %}
|
||||||
|
- <a href="{{ pathto(post.docname) }}{{ anchor(post) }}">{{ post.title }}</a>
|
||||||
|
</p>
|
||||||
|
{% if 0 %}<ul class="ablog-archive">{% include "postcard2.html" %}</ul>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{% for post in collection %}
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2><a href="{{ pathto(post.docname) }}{{ anchor(post) }}">{{ post.title }}</a></h2>
|
||||||
|
|
||||||
|
<ul class="ablog-archive">
|
||||||
|
<li>{% if post.published %}
|
||||||
|
{% if fa %}<i class="fa fa-calendar"></i>{% endif %}
|
||||||
|
{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %}
|
||||||
|
{% if fa %}<i class="fa fa-pencil"></i>{% endif %}
|
||||||
|
{% if post.date %}{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %} Draft {% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% include "postcard2.html" %}</ul>
|
||||||
|
{{ post.to_html(collection.docname) }}
|
||||||
|
<p><a href="{{ pathto(post.docname) }}">{{ _("Read more ...") }}</a></p>
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
10
sphinx_nervproject_theme/ablog/languages.html
Normal file
10
sphinx_nervproject_theme/ablog/languages.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% if ablog.language %}
|
||||||
|
<h3><a href="{{ pathto(ablog.language.path) }}">{{ gettext('Languages') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% for coll in ablog.language %}
|
||||||
|
{% if coll %}
|
||||||
|
<li><a href="{{ pathto(coll.docname) }}">{{ coll }} ({{ coll|length }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
10
sphinx_nervproject_theme/ablog/locations.html
Normal file
10
sphinx_nervproject_theme/ablog/locations.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% if ablog.location %}
|
||||||
|
<h3><a href="{{ pathto(ablog.location.path) }}">{{ gettext('Locations') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% for coll in ablog.location %}
|
||||||
|
{% if coll %}
|
||||||
|
<li><a href="{{ pathto(coll.docname) }}">{{ coll }} ({{ coll|length }})</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
54
sphinx_nervproject_theme/ablog/page.html
Normal file
54
sphinx_nervproject_theme/ablog/page.html
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% set fa = ablog.fontawesome %}
|
||||||
|
{%- block extrahead %}
|
||||||
|
{{ super() }}
|
||||||
|
{% if feed_path %}
|
||||||
|
<link rel="alternate" type="application/atom+xml" href="{{ pathto(feed_path, 1) }}/atom.xml" title="{{ feed_title }}">
|
||||||
|
{% endif %}
|
||||||
|
{% if ablog.fontawesome_link_cdn%}
|
||||||
|
<link href="{{ ablog.fontawesome_link_cdn }}" rel="stylesheet">
|
||||||
|
{% elif ablog.fontawesome_css_file %}
|
||||||
|
<link rel="stylesheet" href="{{ pathto('_static/' + ablog.fontawesome_css_file, 1) }}" type="text/css" />
|
||||||
|
{% endif %}
|
||||||
|
<style type="text/css">
|
||||||
|
ul.ablog-archive {list-style: none; overflow: auto; margin-left: 0px}
|
||||||
|
ul.ablog-archive li {float: left; margin-right: 5px; font-size: 80%}
|
||||||
|
ul.postlist a {font-style: italic;}
|
||||||
|
ul.postlist-style-disc {list-style-type: disc;}
|
||||||
|
ul.postlist-style-none {list-style-type: none;}
|
||||||
|
ul.postlist-style-circle {list-style-type: circle;}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{{ body }}
|
||||||
|
<div class="section">
|
||||||
|
{% if pagename in ablog %}
|
||||||
|
{% include "postnavy.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% if ablog.disqus_shortname and ablog.blog_baseurl and
|
||||||
|
(not ablog[pagename].nocomments) and
|
||||||
|
((pagename in ablog and (ablog[pagename].published or
|
||||||
|
ablog.disqus_drafts)) or
|
||||||
|
(not pagename in ablog and ablog.disqus_pages)) %}
|
||||||
|
<div class="section">
|
||||||
|
<h2>Comments</h2>
|
||||||
|
<div id="disqus_thread"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var disqus_shortname = '{{ ablog.disqus_shortname }}';
|
||||||
|
var disqus_identifier = '{{ablog.page_id(pagename)}}';
|
||||||
|
var disqus_title = '{{title|e}}';
|
||||||
|
var disqus_url = '{{ablog.page_url(pagename)}}';
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||||
|
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
||||||
|
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||||
|
<a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
21
sphinx_nervproject_theme/ablog/postcard.html
Normal file
21
sphinx_nervproject_theme/ablog/postcard.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% if pagename in ablog %}
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="postcard">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
{% set fa = ablog.fontawesome %}
|
||||||
|
{% set post = ablog[pagename] %}
|
||||||
|
<h2>
|
||||||
|
{% if post.published %}
|
||||||
|
{% if fa %}<i class="fa fa-calendar"></i>{% endif %}
|
||||||
|
{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %}
|
||||||
|
{% if fa %}<i class="fa fa-pencil"></i>{% endif %}
|
||||||
|
{% if post.date %}{{ post.date.strftime(ablog.post_date_format) }}
|
||||||
|
{% else %} Draft {% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% include "postcard2.html" %}
|
||||||
|
</ul>
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
68
sphinx_nervproject_theme/ablog/postcard2.html
Normal file
68
sphinx_nervproject_theme/ablog/postcard2.html
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
{% if post.published and post.date != post.update %}
|
||||||
|
<li id="published" ><span>{% if fa %}<i class="fa fa-pencil-square-o"></i>{% else %}{{ gettext('Update') }}:{% endif %}</span>
|
||||||
|
{{ post.update.strftime(ablog.post_date_format) }}</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.author %}
|
||||||
|
<li id="author"><span>{% if fa %}<i class="fa-fw fa fa-user"></i>{% else %}{{ gettext('Author') }}:{% endif %}</span>
|
||||||
|
{% for coll in post.author %}
|
||||||
|
{% if coll|length %}
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a>{% if loop.index < post.author|length %},{% endif %}
|
||||||
|
{% else %}{{ coll }}{% if loop.index < post.author|length %},{% endif %}{% endif %}
|
||||||
|
{% endfor %}</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.location %}
|
||||||
|
<li id="location"><span>{% if fa %}<i class="fa-fw fa fa-location-arrow"></i>{% else %}{{ gettext('Location') }}:{% endif %}</span>
|
||||||
|
{% for coll in post.location %}
|
||||||
|
{% if coll|length %}
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a>{% if loop.index < post.location|length %},{% endif %}
|
||||||
|
{% else %}{{ coll }}{% if loop.index < post.location|length %},{% endif %}{% endif %}
|
||||||
|
{% endfor %}</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.language %}
|
||||||
|
<li id="language"><span>{% if fa %}<i class="fa-fw fa fa-language"></i>{% else %}{{ gettext('Language') }}:{% endif %}</span>
|
||||||
|
{% for coll in post.language %}
|
||||||
|
{% if coll|length %}
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a>{% if loop.index < post.language|length %},{% endif %}
|
||||||
|
{% else %}{{ coll }}{% if loop.index < post.language|length %},{% endif %}{% endif %}
|
||||||
|
{% endfor %}</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.category %}
|
||||||
|
<li id="category"><span>{% if fa %}<i class="fa-fw fa fa-folder-open"></i>{% else %}{{ gettext('Category') }}:{% endif %}</span>
|
||||||
|
{% for coll in post.category %}
|
||||||
|
{% if coll|length %}
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a>{% if loop.index < post.category|length %},{% endif %}
|
||||||
|
{% else %}{{ coll }}{% if loop.index < post.category|length %},{% endif %}{% endif %}
|
||||||
|
{% endfor %}</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if post.tags %}
|
||||||
|
<li id="tags"><span>{% if post.tags|length > 1 %}{% if fa %}<i class="fa-fw fa fa-tags"></i>{% else %}{{ gettext('Tags') }}:{% endif %}
|
||||||
|
{% else %}{% if fa %}<i class="fa-fw fa fa-tag"></i>{% else %}{{ gettext('Tag') }}:{% endif %}{% endif %}</span>
|
||||||
|
{% for coll in post.tags %}
|
||||||
|
{% if coll|length %}
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a>{% if loop.index < post.tags|length %}{% endif %}
|
||||||
|
{% else %}{{ coll }}{% if loop.index < post.tags|length %}{% endif %}{% endif %}
|
||||||
|
{% endfor %}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if ablog.disqus_shortname and (ablog[pagename].published or ablog.disqus_drafts) %}
|
||||||
|
<li id="comments">
|
||||||
|
<script type="text/javascript">
|
||||||
|
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
|
||||||
|
var disqus_shortname = '{{ ablog.disqus_shortname }}'; // required: replace example with your forum shortname
|
||||||
|
|
||||||
|
/* * * DON'T EDIT BELOW THIS LINE * * */
|
||||||
|
(function () {
|
||||||
|
var s = document.createElement('script'); s.async = true;
|
||||||
|
s.type = 'text/javascript';
|
||||||
|
s.src = '//' + disqus_shortname + '.disqus.com/count.js';
|
||||||
|
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
|
||||||
|
}());
|
||||||
|
</script>
|
||||||
|
{% if fa %}<i class="fa-fw fa fa-comments"></i>{% endif %}
|
||||||
|
<a href="{% if pagename != post.docname%}{{ pathto(post.docname) }}{% endif %}#disqus_thread" data-disqus-identifier="/{{post.docname}}/"> {% if not fa %}Comments{% endif %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
25
sphinx_nervproject_theme/ablog/postnavy.html
Normal file
25
sphinx_nervproject_theme/ablog/postnavy.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{# prev/next are not set for drafts #}
|
||||||
|
{% set post = ablog[pagename] %}
|
||||||
|
{% if post.published %}
|
||||||
|
<div class="section">
|
||||||
|
<span style="float: left;">
|
||||||
|
{% if post.prev %}
|
||||||
|
{% if not ablog.fontawesome %}{{ gettext('Previous') }}: {% endif %}
|
||||||
|
<a href="{{ pathto(post.prev.docname) }}{{ anchor(post.prev) }}">
|
||||||
|
{% if ablog.fontawesome %}<i class="fa fa-arrow-circle-left"></i>{% endif %}
|
||||||
|
{{ post.prev.title }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span> </span>
|
||||||
|
<span style="float: right;">
|
||||||
|
{% if post.next %}
|
||||||
|
{% if not ablog.fontawesome %}{{ gettext('Next') }}: {% endif %}
|
||||||
|
<a href="{{ pathto(post.next.docname) }}{{ anchor(post.next) }}">
|
||||||
|
{{ post.next.title }}
|
||||||
|
{% if ablog.fontawesome %}<i class="fa fa-arrow-circle-right"></i>{% endif %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
12
sphinx_nervproject_theme/ablog/recentposts.html
Normal file
12
sphinx_nervproject_theme/ablog/recentposts.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{% if ablog %}
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="recent">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<h3><a href="{{ pathto(ablog.blog_path) }}">{{ gettext('Recent Posts') }}</a></h3>
|
||||||
|
<ul>
|
||||||
|
{% set pcount = 1 %}
|
||||||
|
{% for recent in ablog.recent(5, pagename) %}
|
||||||
|
<li><a href="{{ pathto(recent.docname) }}{{ anchor(recent) }}">{{ recent.date.strftime(ablog.post_date_format_short) + " - " + recent.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
9
sphinx_nervproject_theme/ablog/redirect.html
Normal file
9
sphinx_nervproject_theme/ablog/redirect.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{%- extends "!layout.html" %}
|
||||||
|
{%- block extrahead %}
|
||||||
|
{{ super() }}
|
||||||
|
<meta http-equiv="refresh" content="{{ ablog.post_redirect_refresh }}; url={{ pathto(redirect) }}" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
You are being redirected to <a href="{{ pathto(redirect) }}">{{ post.title }}</a> in {{ ablog.post_redirect_refresh }} seconds;
|
||||||
|
{% endblock %}
|
24
sphinx_nervproject_theme/ablog/tagcloud.html
Normal file
24
sphinx_nervproject_theme/ablog/tagcloud.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{% if ablog.tags %}
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="tags">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<h3><a href="{{ pathto(ablog.tags.path) }}">{{ gettext('Tags') }}</a></h3>
|
||||||
|
<style type="text/css">
|
||||||
|
ul.ablog-cloud {list-style: none; overflow: auto;}
|
||||||
|
ul.ablog-cloud li {float: left; height: 20pt; line-height: 18pt; margin-right: 5px;}
|
||||||
|
ul.ablog-cloud a {text-decoration: none; vertical-align: middle;}
|
||||||
|
li.ablog-cloud-1{font-size: 80%;}
|
||||||
|
li.ablog-cloud-2{font-size: 95%;}
|
||||||
|
li.ablog-cloud-3{font-size: 110%;}
|
||||||
|
li.ablog-cloud-4{font-size: 125%;}
|
||||||
|
li.ablog-cloud-5{font-size: 140%;}
|
||||||
|
</style>
|
||||||
|
<ul class="ablog-cloud">
|
||||||
|
{% for coll in ablog.tags %}
|
||||||
|
{% if coll %}
|
||||||
|
<li class="ablog-cloud ablog-cloud-{{ coll.relsize(5, 1) }}">
|
||||||
|
<a href="{{ pathto(coll.docname) }}">{{ coll }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div></div>
|
||||||
|
{% endif %}
|
56
sphinx_nervproject_theme/domainindex.html
Normal file
56
sphinx_nervproject_theme/domainindex.html
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{#
|
||||||
|
basic/domainindex.html
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Template for domain indices (module index, ...).
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
#}
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% set title = indextitle %}
|
||||||
|
{% block extrahead %}
|
||||||
|
{{ super() }}
|
||||||
|
{% if not embedded and collapse_index %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
DOCUMENTATION_OPTIONS.COLLAPSE_INDEX = true;
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
{%- set groupid = idgen() %}
|
||||||
|
|
||||||
|
<h1>{{ indextitle }}</h1>
|
||||||
|
|
||||||
|
<div class="modindex-jumpbox">
|
||||||
|
{%- for (letter, entries) in content %}
|
||||||
|
<a href="#cap-{{ letter }}"><strong>{{ letter }}</strong></a>
|
||||||
|
{%- if not loop.last %} | {% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="indextable modindextable">
|
||||||
|
{%- for letter, entries in content %}
|
||||||
|
<tr class="pcap"><td></td><td> </td><td></td></tr>
|
||||||
|
<tr class="cap" id="cap-{{ letter }}"><td></td><td>
|
||||||
|
<strong>{{ letter }}</strong></td><td></td></tr>
|
||||||
|
{%- for (name, grouptype, page, anchor, extra, qualifier, description)
|
||||||
|
in entries %}
|
||||||
|
<tr{% if grouptype == 2 %} class="cg-{{ groupid.current() }}"{% endif %}>
|
||||||
|
<td>{% if grouptype == 1 -%}
|
||||||
|
<img src="{{ pathto('_static/minus.png', 1) }}" class="toggler"
|
||||||
|
id="toggle-{{ groupid.next() }}" style="display: none" alt="-" />
|
||||||
|
{%- endif %}</td>
|
||||||
|
<td>{% if grouptype == 2 %}   {% endif %}
|
||||||
|
{% if page %}<a href="{{ pathto(page) }}#{{ anchor }}">{% endif -%}
|
||||||
|
<code class="xref">{{ name|e }}</code>
|
||||||
|
{%- if page %}</a>{% endif %}
|
||||||
|
{%- if extra %} <em>({{ extra|e }})</em>{% endif -%}
|
||||||
|
</td><td>{% if qualifier %}<strong>{{ qualifier|e }}:</strong>{% endif %}
|
||||||
|
<em>{{ description|e }}</em></td></tr>
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
75
sphinx_nervproject_theme/genindex.html
Normal file
75
sphinx_nervproject_theme/genindex.html
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{#
|
||||||
|
basic/genindex.html
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Template for an "all-in-one" index.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
#}
|
||||||
|
{% macro indexentries(firstname, links) %}
|
||||||
|
{%- if links -%}
|
||||||
|
<a href="{{ links[0][1] }}">
|
||||||
|
{%- if links[0][0] %}<strong>{% endif -%}
|
||||||
|
{{ firstname|e }}
|
||||||
|
{%- if links[0][0] %}</strong>{% endif -%}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{%- for ismain, link in links[1:] -%}
|
||||||
|
, <a href="{{ link }}">{% if ismain %}<strong>{% endif -%}
|
||||||
|
[{{ loop.index }}]
|
||||||
|
{%- if ismain %}</strong>{% endif -%}
|
||||||
|
</a>
|
||||||
|
{%- endfor %}
|
||||||
|
{%- else %}
|
||||||
|
{{ firstname|e }}
|
||||||
|
{%- endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% set title = _('Index') %}
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<h1 id="index">{{ _('Index') }}</h1>
|
||||||
|
|
||||||
|
<div class="genindex-jumpbox">
|
||||||
|
{% for key, dummy in genindexentries -%}
|
||||||
|
<a href="#{{ key }}"><strong>{{ key }}</strong></a>
|
||||||
|
{% if not loop.last %}| {% endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- for key, entries in genindexentries %}
|
||||||
|
<h2 id="{{ key }}">{{ key }}</h2>
|
||||||
|
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||||
|
{%- for column in entries|slice_index(2) if column %}
|
||||||
|
<td style="width: 33%; vertical-align: top;"><ul>
|
||||||
|
{%- for entryname, (links, subitems, _) in column %}
|
||||||
|
<li>{{ indexentries(entryname, links) }}
|
||||||
|
{%- if subitems %}
|
||||||
|
<ul>
|
||||||
|
{%- for subentryname, subentrylinks in subitems %}
|
||||||
|
<li>{{ indexentries(subentryname, subentrylinks) }}</li>
|
||||||
|
{%- endfor %}
|
||||||
|
</ul>
|
||||||
|
{%- endif -%}</li>
|
||||||
|
{%- endfor %}
|
||||||
|
</ul></td>
|
||||||
|
{%- endfor %}
|
||||||
|
</tr></table>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebarrel %}
|
||||||
|
{% if split_index %}
|
||||||
|
<h4>{{ _('Index') }}</h4>
|
||||||
|
<p>{% for key, dummy in genindexentries -%}
|
||||||
|
<a href="{{ pathto('genindex-' + key) }}"><strong>{{ key }}</strong></a>
|
||||||
|
{% if not loop.last %}| {% endif %}
|
||||||
|
{%- endfor %}</p>
|
||||||
|
|
||||||
|
<p><a href="{{ pathto('genindex-all') }}"><strong>{{ _('Full index on one page') }}</strong></a></p>
|
||||||
|
{% endif %}
|
||||||
|
{{ super() }}
|
||||||
|
{% endblock %}
|
99
sphinx_nervproject_theme/layout.html
Normal file
99
sphinx_nervproject_theme/layout.html
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html {% if language is not none %} lang="{{ language }}"{% endif %}>
|
||||||
|
<head>
|
||||||
|
<meta charset="{{ encoding }}">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
{{- metatags }}
|
||||||
|
{%- block htmltitle %}
|
||||||
|
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||||
|
{%- endblock %}
|
||||||
|
{# <meta name="description" content="{{ description }}"> #}
|
||||||
|
{%- block css %}
|
||||||
|
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1)}}">
|
||||||
|
<link rel="stylesheet" href="{{ pathto('_static/theme.css', 1)}}">
|
||||||
|
<link rel="stylesheet" href="{{ pathto('_static/sphinx_nervproject_theme.css', 1)}}">
|
||||||
|
{%- for css in css_files %}
|
||||||
|
{%- if css|attr("rel") %}
|
||||||
|
<link rel="{{ css.rel }}" href="{{ pathto(css.filename, 1) }}" type="text/css"{% if css.title is not none %} title="{{ css.title }}"{% endif %} />
|
||||||
|
{%- else %}
|
||||||
|
<link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{%- block scripts %}
|
||||||
|
{# FIXME: use link-preload #}
|
||||||
|
<script type="text/javascript" id="documentation_options" data-url_root="{{ pathto('', 1) }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
|
||||||
|
|
||||||
|
<!-- sphinx script_files -->
|
||||||
|
{%- for scriptfile in script_files %}
|
||||||
|
{{ js_tag(scriptfile) }}
|
||||||
|
{%- endfor %}
|
||||||
|
|
||||||
|
{# press js #}
|
||||||
|
<script src="{{ pathto('_static/theme-vendors.js', 1)}}"></script>
|
||||||
|
<script src="{{ pathto('_static/theme.js', 1)}}" defer></script>
|
||||||
|
{%- endblock %}
|
||||||
|
{%- if pageurl %}
|
||||||
|
<link rel="canonical" href="{{ pageurl }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{# TODO: opensearch #}
|
||||||
|
{%- if favicon %}
|
||||||
|
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
|
{%- include "util/linktags.html" %}
|
||||||
|
{%- block extrahead %} {% endblock %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="app" class="theme-container" :class="pageClasses">
|
||||||
|
{%- block container %}
|
||||||
|
{%- block header %}{%- include "util/navbar.html" %}{% endblock %}
|
||||||
|
|
||||||
|
{# close sidebar when clicked out of it #}
|
||||||
|
<div class="sidebar-mask" @click="toggleSidebar(false)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- block sidebar %}
|
||||||
|
<sidebar @toggle-sidebar="toggleSidebar">
|
||||||
|
{# sidebar navlinks displayed only on mobile #}
|
||||||
|
<navlinks>
|
||||||
|
{% block side_links %}
|
||||||
|
{%- include "util/navlinks.html" %}
|
||||||
|
{%- include "util/extlinks.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
</navlinks>
|
||||||
|
{%- if sidebars != None %}
|
||||||
|
{%- for sidebartemplate in sidebars %}
|
||||||
|
{%- include sidebartemplate %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- endif %}
|
||||||
|
</sidebar>
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
<page>
|
||||||
|
{%- block document %}
|
||||||
|
{% block body_header %}
|
||||||
|
{%- include "util/bodyheader.html" %}
|
||||||
|
{%- endblock body_header %}
|
||||||
|
<div class="content" role="main">
|
||||||
|
{% block body %} {% endblock %}
|
||||||
|
</div>
|
||||||
|
<div class="page-nav">
|
||||||
|
<div class="inner">
|
||||||
|
{%- block footer %}
|
||||||
|
{%- include "util/pagenav.html" %}
|
||||||
|
{%- include "util/footer.html" %}
|
||||||
|
{%- endblock footer %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endblock %}
|
||||||
|
</page>
|
||||||
|
|
||||||
|
{%- endblock container %}
|
||||||
|
</div>
|
||||||
|
{% block footer_scripts %}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
4
sphinx_nervproject_theme/page.html
Normal file
4
sphinx_nervproject_theme/page.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% block body %}
|
||||||
|
{{ body }}
|
||||||
|
{% endblock %}
|
62
sphinx_nervproject_theme/search.html
Normal file
62
sphinx_nervproject_theme/search.html
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{#
|
||||||
|
basic/search.html
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Template for the search page.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
#}
|
||||||
|
{%- extends "layout.html" %}
|
||||||
|
{% set title = _('Search') %}
|
||||||
|
|
||||||
|
{%- block scripts %}
|
||||||
|
{{ super() }}
|
||||||
|
<script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
|
||||||
|
{%- endblock %}
|
||||||
|
|
||||||
|
{% block extrahead %}
|
||||||
|
<script type="text/javascript" src="{{ pathto('searchindex.js', 1) }}" defer></script>
|
||||||
|
{# this is used when loading the search index using $.ajax fails,
|
||||||
|
such as on Chrome for documents on localhost #}
|
||||||
|
<script type="text/javascript" id="searchindexloader"></script>
|
||||||
|
{{ super() }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
<h1 id="search-documentation">{{ _('Search') }}</h1>
|
||||||
|
<div id="fallback" class="admonition warning">
|
||||||
|
<script type="text/javascript">$('#fallback').hide();</script>
|
||||||
|
<p>
|
||||||
|
{% trans %}Please activate JavaScript to enable the search
|
||||||
|
functionality.{% endtrans %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
{% trans %}From here you can search these documents. Enter your search
|
||||||
|
words into the box below and click "search". Note that the search
|
||||||
|
function will automatically search for all of the words. Pages
|
||||||
|
containing fewer words won't appear in the result list.{% endtrans %}
|
||||||
|
</p>
|
||||||
|
<form action="" method="get">
|
||||||
|
<input type="text" name="q" value="" />
|
||||||
|
<input type="submit" value="{{ _('search') }}" />
|
||||||
|
<span id="search-progress" style="padding-left: 10px"></span>
|
||||||
|
</form>
|
||||||
|
{% if search_performed %}
|
||||||
|
<h2>{{ _('Search Results') }}</h2>
|
||||||
|
{% if not search_results %}
|
||||||
|
<p>{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div id="search-results">
|
||||||
|
{% if search_results %}
|
||||||
|
<ul>
|
||||||
|
{% for href, caption, context in search_results %}
|
||||||
|
<li><a href="{{ pathto(item.href) }}">{{ caption }}</a>
|
||||||
|
<div class="context">{{ context|e }}</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Bold.ttf
Normal file
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Bold.ttf
Normal file
Binary file not shown.
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-BoldItalic.ttf
Normal file
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Italic.ttf
Normal file
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Italic.ttf
Normal file
Binary file not shown.
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Regular.ttf
Normal file
BIN
sphinx_nervproject_theme/static/fonts/hack/Hack-Regular.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
sphinx_nervproject_theme/static/fonts/luciole/Luciole-Bold.ttf
Normal file
BIN
sphinx_nervproject_theme/static/fonts/luciole/Luciole-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
14
sphinx_nervproject_theme/static/fonts/luciole/ReadMe.txt
Normal file
14
sphinx_nervproject_theme/static/fonts/luciole/ReadMe.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Ces fontes sont distribuées gratuitement sous Licence publique Creative Commons Attribution 4.0 International :
|
||||||
|
https://creativecommons.org/licenses/by/4.0/legalcode.fr
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
These fonts are freely available under Creative Commons Attribution 4.0 International Public License:
|
||||||
|
https://creativecommons.org/licenses/by/4.0/legalcode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Luciole © Laurent Bourcellier & Jonathan Perez
|
172
sphinx_nervproject_theme/static/sphinx_nervproject_theme.css
Normal file
172
sphinx_nervproject_theme/static/sphinx_nervproject_theme.css
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Defines default styles specific to Sphinx Press,
|
||||||
|
* on top of VuePress styles
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FONTS FOR THE CODE - will fall back to monospace if unavailable */
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Hack;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("fonts/hack/Hack-Regular.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Hack;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("fonts/hack/Hack-Bold.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Hack;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
src: url("fonts/hack/Hack-Bold-Italic.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Hack;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
src: url("fonts/hack/Hack-Regular-Italic.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Luciole;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("fonts/luciole/Luciole-Regular.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Luciole;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: normal;
|
||||||
|
src: url("fonts/luciole/Luciole-Bold.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Luciole;
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
src: url("fonts/luciole/Luciole-Bold-Italic.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: Luciole;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: italic;
|
||||||
|
src: url("fonts/luciole/Luciole-Regular-Italic.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKES MAIN TEXT SECTION LARGER */
|
||||||
|
.content:not(.custom) {
|
||||||
|
max-width: 840px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* THE SECTION BELOW DEFINES THE APPEARANCE OF AUTODOC-GENERATED DOCS */
|
||||||
|
|
||||||
|
.sig-name.descname {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 0 3px; /* creates a perfect grey rectangle*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.sig-param {
|
||||||
|
font-family: 'Hack', monospace;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sig-paren {
|
||||||
|
margin-left: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.field-odd, dt.field-even, p.rubric {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4d6a86
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-inline-start: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd.field-odd p strong {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.method, dl.function {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewcode-link {
|
||||||
|
margin-left: 1em;
|
||||||
|
color: #9ad8bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* THE SECTION BELOW DEFINES THE APPEARANCE OF TABLE-OF-CONTENTS */
|
||||||
|
|
||||||
|
/* color fixes for table of contents */
|
||||||
|
.toc-backref {
|
||||||
|
/* TOCS cause all your section titles to go green. Pouah! */
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents.topic p.topic-title {
|
||||||
|
/* Hide all TOC titles */
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents.topic {
|
||||||
|
margin-bottom: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* THE SECTION BELOW CHANGES CODE FONTS FOR BETTER 80-CHARS READABILITY */
|
||||||
|
code, pre {
|
||||||
|
font-family: 'Hack', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
code, pre {
|
||||||
|
font-family: 'Hack', monospace;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote h2 {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* THE SECTION BELOW FIXES A SPHINX-MERMAID OPACITY PROBLEM */
|
||||||
|
.content .section {
|
||||||
|
opacity: 1.0 !important;
|
||||||
|
}
|
||||||
|
.section {
|
||||||
|
opacity: 1.0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAKES SPHINX SYNTAX figure:: :align:center WORK AGAIN */
|
||||||
|
.figure.align-center {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Luciole;
|
||||||
|
}
|
1
sphinx_nervproject_theme/static/theme-vendors.js
Symbolic link
1
sphinx_nervproject_theme/static/theme-vendors.js
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../ui/dist/js/chunk-vendors.js
|
1
sphinx_nervproject_theme/static/theme.css
Symbolic link
1
sphinx_nervproject_theme/static/theme.css
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../ui/dist/css/app.css
|
1
sphinx_nervproject_theme/static/theme.js
Symbolic link
1
sphinx_nervproject_theme/static/theme.js
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../ui/dist/js/app.js
|
9
sphinx_nervproject_theme/theme.conf
Normal file
9
sphinx_nervproject_theme/theme.conf
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = css/theme.css # required by sphinx
|
||||||
|
pygments_style = paraiso-dark
|
||||||
|
sidebars = util/searchbox.html, util/sidetoc.html
|
||||||
|
|
||||||
|
[options]
|
||||||
|
analytics_id =
|
||||||
|
external_links =
|
16
sphinx_nervproject_theme/util/bodyheader.html
Normal file
16
sphinx_nervproject_theme/util/bodyheader.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<div class="body-header" role="navigation" aria-label="navigation">
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<ul class="breadcrumbs">
|
||||||
|
<li><a href="{{ pathto(master_doc) }}">{{ _('Docs') }}</a> »</li>
|
||||||
|
{% for doc in parents %}
|
||||||
|
<li><a href="{{ doc.link|e }}">{{ doc.title }}</a> »</li>
|
||||||
|
{% endfor %}
|
||||||
|
<li>{{ title }}</li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body_header_nav %}
|
||||||
|
{%- include "util/pagenav.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
<hr>
|
11
sphinx_nervproject_theme/util/extlinks.html
Normal file
11
sphinx_nervproject_theme/util/extlinks.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{# external links, i.e. #}
|
||||||
|
{% if theme_external_links %}
|
||||||
|
{% for (label, url) in theme_external_links %}
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="{{ url }}"
|
||||||
|
class="nav-link external">
|
||||||
|
{{ label }} <outboundlink/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
19
sphinx_nervproject_theme/util/footer.html
Normal file
19
sphinx_nervproject_theme/util/footer.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="footer" role="contentinfo">
|
||||||
|
{%- if show_copyright %}
|
||||||
|
{%- if hasdoc('copyright') %}
|
||||||
|
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
|
||||||
|
{%- else %}
|
||||||
|
{% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- if last_updated %}
|
||||||
|
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- if show_sphinx %}
|
||||||
|
<br>
|
||||||
|
{% trans sphinx_version=sphinx_version|e %}Created using <a
|
||||||
|
href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }} with
|
||||||
|
<a href="https://www.nerv-project.eu">Nerv Project theme</a>
|
||||||
|
based on <a href="https://github.com/schettino72/sphinx_press_theme">Press Theme</a>.{% endtrans %}
|
||||||
|
{%- endif %}
|
||||||
|
</div>
|
18
sphinx_nervproject_theme/util/linktags.html
Normal file
18
sphinx_nervproject_theme/util/linktags.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{%- if hasdoc('about') %}
|
||||||
|
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- if hasdoc('genindex') %}
|
||||||
|
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- if hasdoc('search') %}
|
||||||
|
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- if hasdoc('copyright') %}
|
||||||
|
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- if next %}
|
||||||
|
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
|
||||||
|
{%- endif %}
|
||||||
|
{%- if prev %}
|
||||||
|
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
|
||||||
|
{%- endif %}
|
16
sphinx_nervproject_theme/util/navbar.html
Normal file
16
sphinx_nervproject_theme/util/navbar.html
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<navbar @toggle-sidebar="toggleSidebar">
|
||||||
|
<router-link to="{{pathto(master_doc)}}" class="home-link">
|
||||||
|
{% if logo %}
|
||||||
|
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="logo"/>
|
||||||
|
{% else %}
|
||||||
|
<span class="site-name">{{ project|e }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<div class="links">
|
||||||
|
<navlinks class="can-hide">
|
||||||
|
{%- include "util/navlinks.html" %}
|
||||||
|
{%- include "util/extlinks.html" %}
|
||||||
|
</navlinks>
|
||||||
|
</div>
|
||||||
|
</navbar>
|
12
sphinx_nervproject_theme/util/navlinks.html
Normal file
12
sphinx_nervproject_theme/util/navlinks.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{# create one link per each toctree from master_doc #}
|
||||||
|
{% if toctree_data|length > 1 %}
|
||||||
|
{% for tree in toctree_data %}
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="{{ tree.href }}"
|
||||||
|
class="nav-link {% if tree.current %} router-link-active{% endif %}">
|
||||||
|
{{tree.title}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
14
sphinx_nervproject_theme/util/pagenav.html
Normal file
14
sphinx_nervproject_theme/util/pagenav.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<ul class="page-nav">
|
||||||
|
{%- if prev %}
|
||||||
|
<li class="prev">
|
||||||
|
<a href="{{ prev.link|e }}"
|
||||||
|
title="{{ _('previous chapter') }}">← {{ prev.title }}</a>
|
||||||
|
</li>
|
||||||
|
{%- endif %}
|
||||||
|
{%- if next %}
|
||||||
|
<li class="next">
|
||||||
|
<a href="{{ next.link|e }}"
|
||||||
|
title="{{ _('next chapter') }}">{{ next.title }} →</a>
|
||||||
|
</li>
|
||||||
|
{%- endif %}
|
||||||
|
</ul>
|
12
sphinx_nervproject_theme/util/searchbox.html
Normal file
12
sphinx_nervproject_theme/util/searchbox.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<div id="searchbox" class="searchbox" role="search">
|
||||||
|
<div class="caption"><span class="caption-text">{{ _('Quick search') }}</span>
|
||||||
|
<div class="searchformwrapper">
|
||||||
|
<form class="search" action="{{ pathto('search') }}" method="get">
|
||||||
|
<input type="text" name="q" />
|
||||||
|
<input type="submit" value="{{ _('Search') }}" />
|
||||||
|
<input type="hidden" name="check_keywords" value="yes" />
|
||||||
|
<input type="hidden" name="area" value="default" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
24
sphinx_nervproject_theme/util/sidetoc.html
Normal file
24
sphinx_nervproject_theme/util/sidetoc.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="main navigation">
|
||||||
|
{% for toc in toctree_data %}
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<p class="caption">
|
||||||
|
<span class="caption-text"><a href="{{ toc.href }}">{{toc.title}}</a></span>
|
||||||
|
</p>
|
||||||
|
<ul class="{% if toc.current %}current{% endif %}">
|
||||||
|
{% for entry in toc.entries %}
|
||||||
|
<li class="toctree-l1 {% if entry.current %}current{% endif %}"><a href="{{ pathto(entry.name) }}" class="reference internal {% if entry.current %}current{% endif %}">{{entry.title}}</a>
|
||||||
|
|
||||||
|
{% if entry.children %}
|
||||||
|
<ul>
|
||||||
|
{% for entry2 in entry.children %}
|
||||||
|
<li class="toctree-l2"><a href="{{entry2.href}}" class="reference internal">{{entry2.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
21
ui/.gitignore
vendored
Normal file
21
ui/.gitignore
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw*
|
21
ui/README.md
Normal file
21
ui/README.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# ui
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
5
ui/babel.config.js
Normal file
5
ui/babel.config.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/app'
|
||||||
|
]
|
||||||
|
}
|
11374
ui/package-lock.json
generated
Normal file
11374
ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
47
ui/package.json
Normal file
47
ui/package.json
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"name": "sphinx_nervproject_theme",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^2.5.16"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^3.0.0-rc.9",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.0.0-rc.9",
|
||||||
|
"@vue/cli-service": "^3.0.0-rc.9",
|
||||||
|
"stylus": "^0.54.5",
|
||||||
|
"stylus-loader": "^3.0.2",
|
||||||
|
"vue-template-compiler": "^2.5.16"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off"
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions",
|
||||||
|
"not ie <= 8"
|
||||||
|
]
|
||||||
|
}
|
83
ui/public/index.html
Normal file
83
ui/public/index.html
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>ui</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
|
||||||
|
<div id="app" class="theme-container" :class="pageClasses">
|
||||||
|
<navbar @toggle-sidebar="toggleSidebar">
|
||||||
|
<router-link to='/' class="home-link">
|
||||||
|
<span class="site-name">Foo</span>
|
||||||
|
</router-link>
|
||||||
|
<div class="links">
|
||||||
|
<navlinks class="can-hide">
|
||||||
|
xxx
|
||||||
|
</navlinks>
|
||||||
|
</div>
|
||||||
|
</navbar>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="sidebar-mask"
|
||||||
|
@click="toggleSidebar(false)"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<sidebar
|
||||||
|
@toggle-sidebar="toggleSidebar"
|
||||||
|
>
|
||||||
|
<navlinks>
|
||||||
|
xxx
|
||||||
|
</navlinks>
|
||||||
|
|
||||||
|
<div class="sidebar-links" role="navigation" aria-label="main navigation">
|
||||||
|
<div class="sidebar-group">
|
||||||
|
<p class="caption"><span class="caption-text">Docs</span></p>
|
||||||
|
<ul class="current">
|
||||||
|
<li class="toctree-l1 current"><a class="current reference internal" href="#">About</a><ul>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="#usage">Usage</a></li>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="#status">Status</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="toctree-l1"><a class="reference internal" href="configuration.html">Configuration</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="caption"><span class="caption-text">Demo</span></p>
|
||||||
|
<ul class="current">
|
||||||
|
<li class="toctree-l1 current"><a class="reference internal" href="index.html">Demo</a>
|
||||||
|
<ul class="current">
|
||||||
|
<li class="toctree-l2 current"><a class="current reference internal" href="#">Basic Specification</a></li>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="admonition.html">Admonitions</a></li>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="domain.html">domain</a></li>
|
||||||
|
<li class="toctree-l2"><a class="reference internal" href="extensions.html">Extensions</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div><!-- sidebar-links -->
|
||||||
|
|
||||||
|
</sidebar>
|
||||||
|
|
||||||
|
<page> <!-- :sidebar-items="sidebarItems"> -->
|
||||||
|
<div class="content">
|
||||||
|
<h1 id="my-page-content">My page content
|
||||||
|
<a class="headerlink" href="my-page-content">¶</a>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<p>section 2</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</page>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
152
ui/src/NavLinks.vue
Normal file
152
ui/src/NavLinks.vue
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
<template>
|
||||||
|
<nav
|
||||||
|
class="nav-links"
|
||||||
|
>
|
||||||
|
<!-- v-if="userLinks.length || repoLink" -->
|
||||||
|
<slot></slot>
|
||||||
|
<!-- <\!-- user links -\-> -->
|
||||||
|
<!-- <div -->
|
||||||
|
<!-- class="nav-item" -->
|
||||||
|
<!-- v-for="item in userLinks" -->
|
||||||
|
<!-- :key="item.link" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <DropdownLink -->
|
||||||
|
<!-- v-if="item.type === 'links'" -->
|
||||||
|
<!-- :item="item" -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- <NavLink -->
|
||||||
|
<!-- v-else -->
|
||||||
|
<!-- :item="item" -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<!-- <\!-- repo link -\-> -->
|
||||||
|
<!-- <a -->
|
||||||
|
<!-- v-if="repoLink" -->
|
||||||
|
<!-- :href="repoLink" -->
|
||||||
|
<!-- class="repo-link" -->
|
||||||
|
<!-- target="_blank" -->
|
||||||
|
<!-- rel="noopener noreferrer" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- {{ repoLabel }} -->
|
||||||
|
<!-- <OutboundLink/> -->
|
||||||
|
<!-- </a> -->
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import DropdownLink from './DropdownLink.vue'
|
||||||
|
// import { resolveNavLinkItem } from './util'
|
||||||
|
// import NavLink from './NavLink.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/*
|
||||||
|
components: { NavLink, DropdownLink },
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
userNav () {
|
||||||
|
return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
|
||||||
|
},
|
||||||
|
|
||||||
|
nav () {
|
||||||
|
const { locales } = this.$site
|
||||||
|
if (locales && Object.keys(locales).length > 1) {
|
||||||
|
const currentLink = this.$page.path
|
||||||
|
const routes = this.$router.options.routes
|
||||||
|
const themeLocales = this.$site.themeConfig.locales || {}
|
||||||
|
const languageDropdown = {
|
||||||
|
text: this.$themeLocaleConfig.selectText || 'Languages',
|
||||||
|
items: Object.keys(locales).map(path => {
|
||||||
|
const locale = locales[path]
|
||||||
|
const text = themeLocales[path] && themeLocales[path].label || locale.lang
|
||||||
|
let link
|
||||||
|
// Stay on the current page
|
||||||
|
if (locale.lang === this.$lang) {
|
||||||
|
link = currentLink
|
||||||
|
} else {
|
||||||
|
// Try to stay on the same page
|
||||||
|
link = currentLink.replace(this.$localeConfig.path, path)
|
||||||
|
// fallback to homepage
|
||||||
|
if (!routes.some(route => route.path === link)) {
|
||||||
|
link = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { text, link }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return [...this.userNav, languageDropdown]
|
||||||
|
}
|
||||||
|
return this.userNav
|
||||||
|
},
|
||||||
|
|
||||||
|
userLinks () {
|
||||||
|
return (this.nav || []).map(link => {
|
||||||
|
return Object.assign(resolveNavLinkItem(link), {
|
||||||
|
items: (link.items || []).map(resolveNavLinkItem)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
repoLink () {
|
||||||
|
const { repo } = this.$site.themeConfig
|
||||||
|
if (repo) {
|
||||||
|
return /^https?:/.test(repo)
|
||||||
|
? repo
|
||||||
|
: `https://github.com/${repo}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
repoLabel () {
|
||||||
|
if (!this.repoLink) return
|
||||||
|
if (this.$site.themeConfig.repoLabel) {
|
||||||
|
return this.$site.themeConfig.repoLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
|
||||||
|
const platforms = ['GitHub', 'GitLab', 'Bitbucket']
|
||||||
|
for (let i = 0; i < platforms.length; i++) {
|
||||||
|
const platform = platforms[i]
|
||||||
|
if (new RegExp(platform, 'i').test(repoHost)) {
|
||||||
|
return platform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Source'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './vuepress/styles/config.styl'
|
||||||
|
|
||||||
|
.nav-links
|
||||||
|
display inline-block
|
||||||
|
a
|
||||||
|
line-height 1.4rem
|
||||||
|
color inherit
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
color $accentColor
|
||||||
|
.nav-item
|
||||||
|
position relative
|
||||||
|
display inline-block
|
||||||
|
margin-left 1.5rem
|
||||||
|
line-height 2rem
|
||||||
|
.repo-link
|
||||||
|
margin-left 1.5rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.nav-links
|
||||||
|
.nav-item, .repo-link
|
||||||
|
margin-left 0
|
||||||
|
|
||||||
|
@media (min-width: $MQMobile)
|
||||||
|
.nav-links a
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
color $textColor
|
||||||
|
.nav-item > a:not(.external)
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
margin-bottom -2px
|
||||||
|
border-bottom 2px solid lighten($accentColor, 8%)
|
||||||
|
</style>
|
81
ui/src/Navbar.vue
Normal file
81
ui/src/Navbar.vue
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<header class="navbar">
|
||||||
|
<SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
|
||||||
|
<slot></slot>
|
||||||
|
|
||||||
|
<!-- <img -->
|
||||||
|
<!-- class="logo" -->
|
||||||
|
<!-- v-if="$site.themeConfig.logo" -->
|
||||||
|
<!-- :src="$withBase($site.themeConfig.logo)" -->
|
||||||
|
<!-- :alt="$siteTitle" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <span -->
|
||||||
|
<!-- class="site-name" -->
|
||||||
|
<!-- v-if="$siteTitle" -->
|
||||||
|
<!-- :class="{ 'can-hide': $site.themeConfig.logo }" -->
|
||||||
|
<!-- >{{ $siteTitle }}</span> -->
|
||||||
|
<!-- </router-link> -->
|
||||||
|
|
||||||
|
<!-- <div class="links"> -->
|
||||||
|
<!-- <AlgoliaSearchBox -->
|
||||||
|
<!-- v-if="isAlgoliaSearch" -->
|
||||||
|
<!-- :options="algolia" -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- <SearchBox v-else-if="$site.themeConfig.search !== false"/> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SidebarButton from './vuepress/SidebarButton.vue'
|
||||||
|
// import AlgoliaSearchBox from '@AlgoliaSearchBox'
|
||||||
|
// import SearchBox from './SearchBox.vue'
|
||||||
|
// import NavLinks from './NavLinks.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { SidebarButton }, // NavLinks, SearchBox, AlgoliaSearchBox },
|
||||||
|
|
||||||
|
// computed: {
|
||||||
|
// algolia () {
|
||||||
|
// return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
|
||||||
|
// },
|
||||||
|
|
||||||
|
// isAlgoliaSearch () {
|
||||||
|
// return this.algolia && this.algolia.apiKey && this.algolia.indexName
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
|
||||||
|
@import './vuepress/styles/config.styl'
|
||||||
|
|
||||||
|
.navbar
|
||||||
|
padding 0.7rem 1.5rem
|
||||||
|
line-height $navbarHeight - 1.4rem
|
||||||
|
position fixed // relative
|
||||||
|
a, span, img
|
||||||
|
display inline-block
|
||||||
|
.logo
|
||||||
|
height $navbarHeight - 1.4rem
|
||||||
|
min-width $navbarHeight - 1.4rem
|
||||||
|
margin-right 0.8rem
|
||||||
|
vertical-align top
|
||||||
|
.site-name
|
||||||
|
font-size 1.3rem
|
||||||
|
font-weight 600
|
||||||
|
color $textColor
|
||||||
|
position relative
|
||||||
|
.links
|
||||||
|
font-size 0.9rem
|
||||||
|
position absolute
|
||||||
|
right 1.5rem
|
||||||
|
top 0.7rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.navbar
|
||||||
|
padding-left 4rem
|
||||||
|
.can-hide
|
||||||
|
display none
|
||||||
|
</style>
|
12
ui/src/OutboundLink.vue
Normal file
12
ui/src/OutboundLink.vue
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<template functional>
|
||||||
|
<svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15">
|
||||||
|
<path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path>
|
||||||
|
<polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.icon.outbound
|
||||||
|
color #aaa
|
||||||
|
display inline-block
|
||||||
|
</style>
|
250
ui/src/Page.vue
Normal file
250
ui/src/Page.vue
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<slot/>
|
||||||
|
|
||||||
|
<!-- <Content :custom="false"/> -->
|
||||||
|
|
||||||
|
<!-- <div class="page-edit"> -->
|
||||||
|
<!-- <div -->
|
||||||
|
<!-- class="edit-link" -->
|
||||||
|
<!-- v-if="editLink" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <a -->
|
||||||
|
<!-- :href="editLink" -->
|
||||||
|
<!-- target="_blank" -->
|
||||||
|
<!-- rel="noopener noreferrer" -->
|
||||||
|
<!-- >{{ editLinkText }}</a> -->
|
||||||
|
<!-- <OutboundLink/> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<!-- <div -->
|
||||||
|
<!-- class="last-updated" -->
|
||||||
|
<!-- v-if="lastUpdated" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <span class="prefix">{{ lastUpdatedText }}: </span> -->
|
||||||
|
<!-- <span class="time">{{ lastUpdated }}</span> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<!-- <div class="page-nav" v-if="prev || next"> -->
|
||||||
|
<!-- <p class="inner"> -->
|
||||||
|
<!-- <span -->
|
||||||
|
<!-- v-if="prev" -->
|
||||||
|
<!-- class="prev" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- ← -->
|
||||||
|
<!-- <router-link -->
|
||||||
|
<!-- v-if="prev" -->
|
||||||
|
<!-- class="prev" -->
|
||||||
|
<!-- :to="prev.path" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- {{ prev.title || prev.path }} -->
|
||||||
|
<!-- </router-link> -->
|
||||||
|
<!-- </span> -->
|
||||||
|
|
||||||
|
<!-- <span -->
|
||||||
|
<!-- v-if="next" -->
|
||||||
|
<!-- class="next" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <router-link -->
|
||||||
|
<!-- v-if="next" -->
|
||||||
|
<!-- :to="next.path" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- {{ next.title || next.path }} -->
|
||||||
|
<!-- </router-link> -->
|
||||||
|
<!-- → -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </p> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<slot name="bottom"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//import { resolvePage, normalize, outboundRE, endingSlashRE } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/*
|
||||||
|
props: ['sidebarItems'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
lastUpdated () {
|
||||||
|
if (this.$page.lastUpdated) {
|
||||||
|
return new Date(this.$page.lastUpdated).toLocaleString(this.$lang)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lastUpdatedText () {
|
||||||
|
if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
|
||||||
|
return this.$themeLocaleConfig.lastUpdated
|
||||||
|
}
|
||||||
|
if (typeof this.$site.themeConfig.lastUpdated === 'string') {
|
||||||
|
return this.$site.themeConfig.lastUpdated
|
||||||
|
}
|
||||||
|
return 'Last Updated'
|
||||||
|
},
|
||||||
|
|
||||||
|
prev () {
|
||||||
|
const prev = this.$page.frontmatter.prev
|
||||||
|
if (prev === false) {
|
||||||
|
return
|
||||||
|
} else if (prev) {
|
||||||
|
return resolvePage(this.$site.pages, prev, this.$route.path)
|
||||||
|
} else {
|
||||||
|
return resolvePrev(this.$page, this.sidebarItems)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
next () {
|
||||||
|
const next = this.$page.frontmatter.next
|
||||||
|
if (next === false) {
|
||||||
|
return
|
||||||
|
} else if (next) {
|
||||||
|
return resolvePage(this.$site.pages, next, this.$route.path)
|
||||||
|
} else {
|
||||||
|
return resolveNext(this.$page, this.sidebarItems)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
editLink () {
|
||||||
|
if (this.$page.frontmatter.editLink === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
repo,
|
||||||
|
editLinks,
|
||||||
|
docsDir = '',
|
||||||
|
docsBranch = 'master',
|
||||||
|
docsRepo = repo
|
||||||
|
} = this.$site.themeConfig
|
||||||
|
|
||||||
|
let path = normalize(this.$page.path)
|
||||||
|
if (endingSlashRE.test(path)) {
|
||||||
|
path += 'README.md'
|
||||||
|
} else {
|
||||||
|
path += '.md'
|
||||||
|
}
|
||||||
|
if (docsRepo && editLinks) {
|
||||||
|
return this.createEditLink(repo, docsRepo, docsDir, docsBranch, path)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
editLinkText () {
|
||||||
|
return (
|
||||||
|
this.$themeLocaleConfig.editLinkText ||
|
||||||
|
this.$site.themeConfig.editLinkText ||
|
||||||
|
`Edit this page`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
|
||||||
|
const bitbucket = /bitbucket.org/
|
||||||
|
if (bitbucket.test(repo)) {
|
||||||
|
const base = outboundRE.test(docsRepo)
|
||||||
|
? docsRepo
|
||||||
|
: repo
|
||||||
|
return (
|
||||||
|
base.replace(endingSlashRE, '') +
|
||||||
|
`/${docsBranch}` +
|
||||||
|
(docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
|
||||||
|
path +
|
||||||
|
`?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = outboundRE.test(docsRepo)
|
||||||
|
? docsRepo
|
||||||
|
: `https://github.com/${docsRepo}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
base.replace(endingSlashRE, '') +
|
||||||
|
`/edit/${docsBranch}` +
|
||||||
|
(docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
|
||||||
|
path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
function resolvePrev (page, items) {
|
||||||
|
return find(page, items, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveNext (page, items) {
|
||||||
|
return find(page, items, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function find (page, items, offset) {
|
||||||
|
const res = []
|
||||||
|
items.forEach(item => {
|
||||||
|
if (item.type === 'group') {
|
||||||
|
res.push(...item.children || [])
|
||||||
|
} else {
|
||||||
|
res.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
const cur = res[i]
|
||||||
|
if (cur.type === 'page' && cur.path === page.path) {
|
||||||
|
return res[i + offset]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './vuepress/styles/config.styl'
|
||||||
|
@require './vuepress/styles/wrapper.styl'
|
||||||
|
|
||||||
|
.page
|
||||||
|
padding-top $navbarHeight
|
||||||
|
padding-bottom 2rem
|
||||||
|
|
||||||
|
.page-edit
|
||||||
|
@extend $wrapper
|
||||||
|
padding-top 1rem
|
||||||
|
padding-bottom 1rem
|
||||||
|
overflow auto
|
||||||
|
.edit-link
|
||||||
|
display inline-block
|
||||||
|
a
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
margin-right 0.25rem
|
||||||
|
.last-updated
|
||||||
|
float right
|
||||||
|
font-size 0.9em
|
||||||
|
.prefix
|
||||||
|
font-weight 500
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
.time
|
||||||
|
font-weight 400
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
.page-nav
|
||||||
|
@extend $wrapper
|
||||||
|
padding-top 1rem
|
||||||
|
padding-bottom 0
|
||||||
|
.inner
|
||||||
|
min-height 2rem
|
||||||
|
margin-top 0
|
||||||
|
border-top 1px solid $borderColor
|
||||||
|
padding-top 1rem
|
||||||
|
overflow auto // clear float
|
||||||
|
.next
|
||||||
|
float right
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.page-edit
|
||||||
|
.edit-link
|
||||||
|
margin-bottom .5rem
|
||||||
|
.last-updated
|
||||||
|
font-size .8em
|
||||||
|
float none
|
||||||
|
text-align left
|
||||||
|
|
||||||
|
</style>
|
5
ui/src/README.md
Normal file
5
ui/src/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
* -> components copied/modified from vuepress
|
||||||
|
|
||||||
|
* Navbar.vue
|
||||||
|
* SidebarButton.vue
|
202
ui/src/Sidebar.vue
Normal file
202
ui/src/Sidebar.vue
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
<template>
|
||||||
|
<div class="sidebar">
|
||||||
|
<slot></slot>
|
||||||
|
<!-- <slot name="top"/> -->
|
||||||
|
<!-- <ul class="sidebar-links" v-if="items.length"> -->
|
||||||
|
<!-- <li v-for="(item, i) in items" :key="i"> -->
|
||||||
|
<!-- <SidebarGroup -->
|
||||||
|
<!-- v-if="item.type === 'group'" -->
|
||||||
|
<!-- :item="item" -->
|
||||||
|
<!-- :first="i === 0" -->
|
||||||
|
<!-- :open="i === openGroupIndex" -->
|
||||||
|
<!-- :collapsable="item.collapsable" -->
|
||||||
|
<!-- @toggle="toggleGroup(i)" -->
|
||||||
|
<!-- /> -->
|
||||||
|
<!-- <SidebarLink v-else :item="item"/> -->
|
||||||
|
<!-- </li> -->
|
||||||
|
<!-- </ul> -->
|
||||||
|
<!-- <slot name="bottom"/> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//import SidebarGroup from './SidebarGroup.vue'
|
||||||
|
//import SidebarLink from './SidebarLink.vue'
|
||||||
|
//import { isActive } from './vuepress/util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
/*
|
||||||
|
components: { SidebarGroup, SidebarLink },
|
||||||
|
|
||||||
|
props: ['items'],
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
openGroupIndex: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.refreshIndex()
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'$route' () {
|
||||||
|
this.refreshIndex()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
refreshIndex () {
|
||||||
|
const index = resolveOpenGroupIndex(
|
||||||
|
this.$route,
|
||||||
|
this.items
|
||||||
|
)
|
||||||
|
if (index > -1) {
|
||||||
|
this.openGroupIndex = index
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleGroup (index) {
|
||||||
|
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
|
||||||
|
},
|
||||||
|
|
||||||
|
isActive (page) {
|
||||||
|
return isActive(this.$route, page.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveOpenGroupIndex (route, items) {
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i]
|
||||||
|
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './vuepress/styles/config.styl'
|
||||||
|
|
||||||
|
.sidebar
|
||||||
|
ul
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
list-style-type none
|
||||||
|
a
|
||||||
|
display inline-block
|
||||||
|
.nav-links
|
||||||
|
display none
|
||||||
|
border-bottom 1px solid $borderColor
|
||||||
|
padding 0.5rem 0 0.75rem 0
|
||||||
|
a
|
||||||
|
font-weight 600
|
||||||
|
.nav-item, .repo-link
|
||||||
|
display block
|
||||||
|
line-height 1.25rem
|
||||||
|
font-size 1.1em
|
||||||
|
padding 0.5rem 0 0.5rem 1.5rem
|
||||||
|
.searchbox
|
||||||
|
font-weight 600
|
||||||
|
font-size 1.1em
|
||||||
|
line-height 1.5rem
|
||||||
|
padding 1rem 0 1.5rem 1.5rem
|
||||||
|
border-bottom 1px solid $borderColor
|
||||||
|
.sidebar-links
|
||||||
|
padding 1.5rem 0
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.sidebar
|
||||||
|
.nav-links
|
||||||
|
display block
|
||||||
|
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||||
|
top calc(1rem - 2px)
|
||||||
|
.sidebar-links
|
||||||
|
padding 1rem 0
|
||||||
|
|
||||||
|
/********************/
|
||||||
|
|
||||||
|
/* rename some classes as no control on what comes from sphinx:
|
||||||
|
- sidebar-heading => caption
|
||||||
|
- sidebar-link => reference
|
||||||
|
- sidebar-sub-headers => toctree-l2
|
||||||
|
Note: sidebar-sub-headers refers to ul in Vuepress
|
||||||
|
while toctree-l2 referes to li in sphinx
|
||||||
|
- active => current
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**** SidebarGroup.vue ***/
|
||||||
|
.sidebar-group
|
||||||
|
&:not(.first)
|
||||||
|
margin-top 1em
|
||||||
|
.sidebar-group
|
||||||
|
padding-left 0.5em
|
||||||
|
&:not(.collapsable)
|
||||||
|
.caption
|
||||||
|
cursor auto
|
||||||
|
color inherit
|
||||||
|
|
||||||
|
.sidebar-group .caption
|
||||||
|
color #999
|
||||||
|
transition color .15s ease
|
||||||
|
cursor pointer
|
||||||
|
font-size 1.1em
|
||||||
|
font-weight bold
|
||||||
|
// text-transform uppercase
|
||||||
|
padding 0 1.5rem
|
||||||
|
margin-top 0
|
||||||
|
margin-bottom 0.5rem
|
||||||
|
&.open, &:hover
|
||||||
|
color inherit
|
||||||
|
.arrow
|
||||||
|
position relative
|
||||||
|
top -0.12em
|
||||||
|
left 0.5em
|
||||||
|
&:.open .arrow
|
||||||
|
top -0.18em
|
||||||
|
|
||||||
|
.sidebar-group-items /* FIXME sphinx toc equivalent */
|
||||||
|
transition height .1s ease-out
|
||||||
|
overflow hidden
|
||||||
|
|
||||||
|
/**** end: SidebarGroup.vue ***/
|
||||||
|
|
||||||
|
/**** SidebarLink.vue ***/
|
||||||
|
/*.sidebar .sidebar-sub-headers*/
|
||||||
|
.sidebar .toctree-l1 ul
|
||||||
|
font-size 0.95em
|
||||||
|
|
||||||
|
.sidebar
|
||||||
|
.toctree-l1 a, .toctree-l2 a
|
||||||
|
font-weight 400
|
||||||
|
display inline-block
|
||||||
|
color $textColor
|
||||||
|
line-height 1.4
|
||||||
|
width: 100%
|
||||||
|
box-sizing: border-box
|
||||||
|
border-left 0.5rem solid transparent
|
||||||
|
&.current
|
||||||
|
color $accentColor
|
||||||
|
font-weight 600
|
||||||
|
&:hover
|
||||||
|
color $accentColor
|
||||||
|
|
||||||
|
// /* extra indication of current, since no support to hight current location */
|
||||||
|
.toctree-l1.current a
|
||||||
|
border-left: .5rem solid lighten($accentColor, 40%)
|
||||||
|
.toctree-l1 a
|
||||||
|
padding 0.35rem 1rem 0.35rem 1.25rem
|
||||||
|
&.current
|
||||||
|
border-left-color $accentColor
|
||||||
|
.toctree-l2 a
|
||||||
|
padding 0.25rem 1rem 0.25rem 1.75rem
|
||||||
|
|
||||||
|
|
||||||
|
/**** end: SidebarLink.vue ***/
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
54
ui/src/main.js
Normal file
54
ui/src/main.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
import './vuepress/styles/theme.styl'
|
||||||
|
import './sphinx-theme.styl'
|
||||||
|
import OutboundLink from './OutboundLink.vue'
|
||||||
|
import Navbar from './Navbar.vue'
|
||||||
|
import NavLinks from './NavLinks.vue'
|
||||||
|
import Sidebar from './Sidebar.vue'
|
||||||
|
import Page from './Page.vue'
|
||||||
|
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
Vue.component('outboundlink', OutboundLink)
|
||||||
|
Vue.component('navbar', Navbar)
|
||||||
|
Vue.component('navlinks', NavLinks)
|
||||||
|
Vue.component('sidebar', Sidebar)
|
||||||
|
Vue.component('page', Page)
|
||||||
|
|
||||||
|
|
||||||
|
// fake router element
|
||||||
|
Vue.component('router-link', {
|
||||||
|
props: ['to'],
|
||||||
|
template: '<a :href="to"><slot></slot></a>',
|
||||||
|
})
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
el: '#app',
|
||||||
|
// taken from Layout.vue
|
||||||
|
data: {
|
||||||
|
isSidebarOpen: false,
|
||||||
|
swUpdateEvent: null
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pageClasses () {
|
||||||
|
//const userPageClass = this.$page.frontmatter.pageClass
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
// 'no-navbar': !this.shouldShowNavbar,
|
||||||
|
'sidebar-open': this.isSidebarOpen,
|
||||||
|
// 'no-sidebar': !this.shouldShowSidebar
|
||||||
|
},
|
||||||
|
// userPageClass
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleSidebar (to) {
|
||||||
|
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
133
ui/src/sphinx-theme.styl
Normal file
133
ui/src/sphinx-theme.styl
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
@require './vuepress/styles/config'
|
||||||
|
|
||||||
|
/* fix anchor link positioning for fixed navbar */
|
||||||
|
// FIXME this is not enough as it works only for section headers
|
||||||
|
$anchorHeight = ($navbarHeight + 0.5rem)
|
||||||
|
.content .section
|
||||||
|
margin-top -($anchorHeight)
|
||||||
|
padding-top $anchorHeight
|
||||||
|
margin-bottom 0
|
||||||
|
&:hover
|
||||||
|
.headerlink
|
||||||
|
opacity: 1
|
||||||
|
|
||||||
|
.content
|
||||||
|
// FIXME: sphinx should provide a citation-reference?
|
||||||
|
.footnote-reference, .label, dt, p
|
||||||
|
margin-top -($navbarHeight)
|
||||||
|
padding-top $navbarHeight
|
||||||
|
& a:focus
|
||||||
|
// remove outline because padding mess it up
|
||||||
|
outline none
|
||||||
|
|
||||||
|
|
||||||
|
/* Use # as symbol for anchor headerlinks */
|
||||||
|
h1, h2, h3, h4, h5, h6
|
||||||
|
&:hover a.headerlink
|
||||||
|
&::after
|
||||||
|
visibility visible
|
||||||
|
content "#"
|
||||||
|
|
||||||
|
a.headerlink
|
||||||
|
font-size 0.85em
|
||||||
|
visibility hidden
|
||||||
|
&:hover
|
||||||
|
text-decoration none
|
||||||
|
|
||||||
|
ul.page-nav
|
||||||
|
list-style none
|
||||||
|
& li
|
||||||
|
display inline-block
|
||||||
|
|
||||||
|
.body-header
|
||||||
|
display flex
|
||||||
|
& ul.page-nav
|
||||||
|
flex-grow 1
|
||||||
|
list-style none
|
||||||
|
list-style-position inside
|
||||||
|
text-align right
|
||||||
|
margin-right 30px
|
||||||
|
& li + li:before
|
||||||
|
content "|"
|
||||||
|
padding 0 1em
|
||||||
|
|
||||||
|
ul.breadcrumbs
|
||||||
|
list-style none
|
||||||
|
& li
|
||||||
|
display inline-block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** index page **/
|
||||||
|
.toctree-wrapper .caption
|
||||||
|
// same as h2
|
||||||
|
font-weight 600
|
||||||
|
line-height 1.25
|
||||||
|
font-size 1.65rem
|
||||||
|
padding-bottom .3rem
|
||||||
|
border-bottom 1px solid $borderColor
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** footer **/
|
||||||
|
.footer
|
||||||
|
clear both
|
||||||
|
min-height 2rem
|
||||||
|
padding-top 1rem
|
||||||
|
overflow auto
|
||||||
|
color grey
|
||||||
|
font-size small
|
||||||
|
line-height 1.5rem
|
||||||
|
|
||||||
|
|
||||||
|
/** pygments style **/
|
||||||
|
.content .highlight
|
||||||
|
border-radius 6px
|
||||||
|
|
||||||
|
// force background color from pygments
|
||||||
|
.content .highlight pre
|
||||||
|
background-color inherit
|
||||||
|
|
||||||
|
.content .highlighted
|
||||||
|
background-color #fbe54e
|
||||||
|
font-weight bold
|
||||||
|
padding 0 4px
|
||||||
|
|
||||||
|
/*** admonitions based on custom-blocks.styl */
|
||||||
|
.admonition
|
||||||
|
padding .1rem 1.5rem
|
||||||
|
border-left-width .5rem
|
||||||
|
border-left-style solid
|
||||||
|
margin 1rem 0
|
||||||
|
// default color
|
||||||
|
background-color #e2e2e2
|
||||||
|
border-color #787878
|
||||||
|
|
||||||
|
.admonition-title
|
||||||
|
font-weight 600
|
||||||
|
margin-bottom -0.4rem
|
||||||
|
&.tip, &.hint
|
||||||
|
background-color #f3f5f7
|
||||||
|
border-color #42b983
|
||||||
|
&.important, &.note
|
||||||
|
background-color #e5f1fb
|
||||||
|
border-color #5faaea
|
||||||
|
&.warning, &.caution
|
||||||
|
background-color rgba(255,229,100,.3)
|
||||||
|
border-color darken(#ffe564, 35%)
|
||||||
|
color darken(#ffe564, 70%)
|
||||||
|
.custom-block-title
|
||||||
|
color darken(#ffe564, 50%)
|
||||||
|
a
|
||||||
|
color $textColor
|
||||||
|
&.danger, &.error
|
||||||
|
background-color #ffe6e6
|
||||||
|
border-color darken(red, 20%)
|
||||||
|
color darken(red, 70%)
|
||||||
|
.custom-block-title
|
||||||
|
color darken(red, 40%)
|
||||||
|
a
|
||||||
|
color $textColor
|
||||||
|
|
||||||
|
blockquote
|
||||||
|
margin-left -0.4rem
|
140
ui/src/vuepress/AlgoliaSearchBox.vue
Normal file
140
ui/src/vuepress/AlgoliaSearchBox.vue
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<template>
|
||||||
|
<form
|
||||||
|
id="search-form"
|
||||||
|
class="algolia-search-wrapper search-box"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="algolia-search-input"
|
||||||
|
class="search-query"
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['options'],
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.initialize()
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
initialize () {
|
||||||
|
Promise.all([
|
||||||
|
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
|
||||||
|
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
|
||||||
|
]).then(([docsearch]) => {
|
||||||
|
docsearch = docsearch.default
|
||||||
|
docsearch(Object.assign(this.options, {
|
||||||
|
debug: true,
|
||||||
|
inputSelector: '#algolia-search-input'
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
options (newValue) {
|
||||||
|
this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
|
||||||
|
this.initialize(newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.algolia-search-wrapper
|
||||||
|
& > span
|
||||||
|
vertical-align middle
|
||||||
|
.algolia-autocomplete
|
||||||
|
line-height normal
|
||||||
|
.ds-dropdown-menu
|
||||||
|
background-color #fff
|
||||||
|
border 1px solid #999
|
||||||
|
border-radius 4px
|
||||||
|
font-size 16px
|
||||||
|
margin 6px 0 0
|
||||||
|
padding 4px
|
||||||
|
text-align left
|
||||||
|
&:before
|
||||||
|
border-color #999
|
||||||
|
[class*=ds-dataset-]
|
||||||
|
border none
|
||||||
|
padding 0
|
||||||
|
.ds-suggestions
|
||||||
|
margin-top 0
|
||||||
|
.ds-suggestion
|
||||||
|
border-bottom 1px solid $borderColor
|
||||||
|
.algolia-docsearch-suggestion--highlight
|
||||||
|
color #2c815b
|
||||||
|
.algolia-docsearch-suggestion
|
||||||
|
border-color $borderColor
|
||||||
|
padding 0
|
||||||
|
.algolia-docsearch-suggestion--category-header
|
||||||
|
padding 5px 10px
|
||||||
|
margin-top 0
|
||||||
|
background $accentColor
|
||||||
|
color #fff
|
||||||
|
font-weight 600
|
||||||
|
.algolia-docsearch-suggestion--highlight
|
||||||
|
background rgba(255, 255, 255, 0.6)
|
||||||
|
.algolia-docsearch-suggestion--wrapper
|
||||||
|
padding 0
|
||||||
|
.algolia-docsearch-suggestion--title
|
||||||
|
font-weight 600
|
||||||
|
margin-bottom 0
|
||||||
|
color $textColor
|
||||||
|
.algolia-docsearch-suggestion--subcategory-column
|
||||||
|
vertical-align top
|
||||||
|
padding 5px 7px 5px 5px
|
||||||
|
border-color $borderColor
|
||||||
|
background #f1f3f5
|
||||||
|
&:after
|
||||||
|
display none
|
||||||
|
.algolia-docsearch-suggestion--subcategory-column-text
|
||||||
|
color #555
|
||||||
|
.algolia-docsearch-footer
|
||||||
|
border-color $borderColor
|
||||||
|
.ds-cursor .algolia-docsearch-suggestion--content
|
||||||
|
background-color #e7edf3 !important
|
||||||
|
color $textColor
|
||||||
|
|
||||||
|
@media (min-width: $MQMobile)
|
||||||
|
.algolia-search-wrapper
|
||||||
|
.algolia-autocomplete
|
||||||
|
.algolia-docsearch-suggestion
|
||||||
|
.algolia-docsearch-suggestion--subcategory-column
|
||||||
|
float none
|
||||||
|
width 150px
|
||||||
|
min-width 150px
|
||||||
|
display table-cell
|
||||||
|
.algolia-docsearch-suggestion--content
|
||||||
|
float none
|
||||||
|
display table-cell
|
||||||
|
width 100%
|
||||||
|
vertical-align top
|
||||||
|
.ds-dropdown-menu
|
||||||
|
min-width 515px !important
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.algolia-search-wrapper
|
||||||
|
.ds-dropdown-menu
|
||||||
|
min-width calc(100vw - 4rem) !important
|
||||||
|
max-width calc(100vw - 4rem) !important
|
||||||
|
.algolia-docsearch-suggestion--wrapper
|
||||||
|
padding 5px 7px 5px 5px !important
|
||||||
|
.algolia-docsearch-suggestion--subcategory-column
|
||||||
|
padding 0 !important
|
||||||
|
background white !important
|
||||||
|
.algolia-docsearch-suggestion--subcategory-column-text:after
|
||||||
|
content " > "
|
||||||
|
font-size 10px
|
||||||
|
line-height 14.4px
|
||||||
|
display inline-block
|
||||||
|
width 5px
|
||||||
|
margin -3px 3px 0
|
||||||
|
vertical-align middle
|
||||||
|
|
||||||
|
</style>
|
181
ui/src/vuepress/DropdownLink.vue
Normal file
181
ui/src/vuepress/DropdownLink.vue
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="dropdown-wrapper"
|
||||||
|
:class="{ open }"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
class="dropdown-title"
|
||||||
|
@click="toggle"
|
||||||
|
>
|
||||||
|
<span class="title">{{ item.text }}</span>
|
||||||
|
<span
|
||||||
|
class="arrow"
|
||||||
|
:class="open ? 'down' : 'right'"
|
||||||
|
></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<DropdownTransition>
|
||||||
|
<ul
|
||||||
|
class="nav-dropdown"
|
||||||
|
v-show="open"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="dropdown-item"
|
||||||
|
:key="subItem.link || index"
|
||||||
|
v-for="(subItem, index) in item.items"
|
||||||
|
>
|
||||||
|
<h4 v-if="subItem.type === 'links'">{{ subItem.text }}</h4>
|
||||||
|
|
||||||
|
<ul
|
||||||
|
class="dropdown-subitem-wrapper"
|
||||||
|
v-if="subItem.type === 'links'"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="dropdown-subitem"
|
||||||
|
:key="childSubItem.link"
|
||||||
|
v-for="childSubItem in subItem.items"
|
||||||
|
>
|
||||||
|
<NavLink :item="childSubItem"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<NavLink
|
||||||
|
v-else
|
||||||
|
:item="subItem"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</DropdownTransition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import NavLink from './NavLink.vue'
|
||||||
|
import DropdownTransition from './DropdownTransition.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { NavLink, DropdownTransition },
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
open: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggle () {
|
||||||
|
this.open = !this.open
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.dropdown-wrapper
|
||||||
|
cursor pointer
|
||||||
|
.dropdown-title
|
||||||
|
display block
|
||||||
|
&:hover
|
||||||
|
border-color transparent
|
||||||
|
.arrow
|
||||||
|
vertical-align middle
|
||||||
|
margin-top -1px
|
||||||
|
margin-left 0.4rem
|
||||||
|
.nav-dropdown
|
||||||
|
.dropdown-item
|
||||||
|
color inherit
|
||||||
|
line-height 1.7rem
|
||||||
|
h4
|
||||||
|
margin 0.45rem 0 0
|
||||||
|
border-top 1px solid #eee
|
||||||
|
padding 0.45rem 1.5rem 0 1.25rem
|
||||||
|
.dropdown-subitem-wrapper
|
||||||
|
padding 0
|
||||||
|
list-style none
|
||||||
|
.dropdown-subitem
|
||||||
|
font-size 0.9em
|
||||||
|
a
|
||||||
|
display block
|
||||||
|
line-height 1.7rem
|
||||||
|
position relative
|
||||||
|
border-bottom none
|
||||||
|
font-weight 400
|
||||||
|
margin-bottom 0
|
||||||
|
padding 0 1.5rem 0 1.25rem
|
||||||
|
&:hover
|
||||||
|
color $accentColor
|
||||||
|
&.router-link-active
|
||||||
|
color $accentColor
|
||||||
|
&::after
|
||||||
|
content ""
|
||||||
|
width 0
|
||||||
|
height 0
|
||||||
|
border-left 5px solid $accentColor
|
||||||
|
border-top 3px solid transparent
|
||||||
|
border-bottom 3px solid transparent
|
||||||
|
position absolute
|
||||||
|
top calc(50% - 2px)
|
||||||
|
left 9px
|
||||||
|
&:first-child h4
|
||||||
|
margin-top 0
|
||||||
|
padding-top 0
|
||||||
|
border-top 0
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.dropdown-wrapper
|
||||||
|
&.open .dropdown-title
|
||||||
|
margin-bottom 0.5rem
|
||||||
|
.nav-dropdown
|
||||||
|
transition height .1s ease-out
|
||||||
|
overflow hidden
|
||||||
|
.dropdown-item
|
||||||
|
h4
|
||||||
|
border-top 0
|
||||||
|
margin-top 0
|
||||||
|
padding-top 0
|
||||||
|
h4, & > a
|
||||||
|
font-size 15px
|
||||||
|
line-height 2rem
|
||||||
|
.dropdown-subitem
|
||||||
|
font-size 14px
|
||||||
|
padding-left 1rem
|
||||||
|
|
||||||
|
@media (min-width: $MQMobile)
|
||||||
|
.dropdown-wrapper
|
||||||
|
height 1.8rem
|
||||||
|
&:hover .nav-dropdown
|
||||||
|
// override the inline style.
|
||||||
|
display block !important
|
||||||
|
.dropdown-title .arrow
|
||||||
|
// make the arrow always down at desktop
|
||||||
|
border-left 4px solid transparent
|
||||||
|
border-right 4px solid transparent
|
||||||
|
border-top 6px solid $arrowBgColor
|
||||||
|
border-bottom 0
|
||||||
|
.nav-dropdown
|
||||||
|
display none
|
||||||
|
// Avoid height shaked by clicking
|
||||||
|
height auto !important
|
||||||
|
box-sizing border-box;
|
||||||
|
max-height calc(100vh - 2.7rem)
|
||||||
|
overflow-y auto
|
||||||
|
position absolute
|
||||||
|
top 100%
|
||||||
|
right 0
|
||||||
|
background-color #fff
|
||||||
|
padding 0.6rem 0
|
||||||
|
border 1px solid #ddd
|
||||||
|
border-bottom-color #ccc
|
||||||
|
text-align left
|
||||||
|
border-radius 0.25rem
|
||||||
|
white-space nowrap
|
||||||
|
margin 0
|
||||||
|
</style>
|
33
ui/src/vuepress/DropdownTransition.vue
Normal file
33
ui/src/vuepress/DropdownTransition.vue
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<template>
|
||||||
|
<transition
|
||||||
|
name="dropdown"
|
||||||
|
@enter="setHeight"
|
||||||
|
@after-enter="unsetHeight"
|
||||||
|
@before-leave="setHeight"
|
||||||
|
>
|
||||||
|
<slot/>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'DropdownTransition',
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setHeight (items) {
|
||||||
|
// explicitly set height so that it can be transitioned
|
||||||
|
items.style.height = items.scrollHeight + 'px'
|
||||||
|
},
|
||||||
|
|
||||||
|
unsetHeight (items) {
|
||||||
|
items.style.height = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.dropdown-enter, .dropdown-leave-to
|
||||||
|
height 0 !important
|
||||||
|
|
||||||
|
</style>
|
161
ui/src/vuepress/Home.vue
Normal file
161
ui/src/vuepress/Home.vue
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
<template>
|
||||||
|
<div class="home">
|
||||||
|
<div class="hero">
|
||||||
|
<img
|
||||||
|
v-if="data.heroImage"
|
||||||
|
:src="$withBase(data.heroImage)"
|
||||||
|
alt="hero"
|
||||||
|
>
|
||||||
|
|
||||||
|
<h1>{{ data.heroText || $title || 'Hello' }}</h1>
|
||||||
|
|
||||||
|
<p class="description">
|
||||||
|
{{ data.tagline || $description || 'Welcome to your VuePress site' }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p
|
||||||
|
class="action"
|
||||||
|
v-if="data.actionText && data.actionLink"
|
||||||
|
>
|
||||||
|
<NavLink
|
||||||
|
class="action-button"
|
||||||
|
:item="actionLink"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="features"
|
||||||
|
v-if="data.features && data.features.length"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="feature"
|
||||||
|
v-for="feature in data.features"
|
||||||
|
>
|
||||||
|
<h2>{{ feature.title }}</h2>
|
||||||
|
<p>{{ feature.details }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Content custom/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="footer"
|
||||||
|
v-if="data.footer"
|
||||||
|
>
|
||||||
|
{{ data.footer }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import NavLink from './NavLink.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { NavLink },
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
data () {
|
||||||
|
return this.$page.frontmatter
|
||||||
|
},
|
||||||
|
|
||||||
|
actionLink () {
|
||||||
|
return {
|
||||||
|
link: this.data.actionLink,
|
||||||
|
text: this.data.actionText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.home
|
||||||
|
padding $navbarHeight 2rem 0
|
||||||
|
max-width 960px
|
||||||
|
margin 0px auto
|
||||||
|
.hero
|
||||||
|
text-align center
|
||||||
|
img
|
||||||
|
max-height 280px
|
||||||
|
display block
|
||||||
|
margin 3rem auto 1.5rem
|
||||||
|
h1
|
||||||
|
font-size 3rem
|
||||||
|
h1, .description, .action
|
||||||
|
margin 1.8rem auto
|
||||||
|
.description
|
||||||
|
max-width 35rem
|
||||||
|
font-size 1.6rem
|
||||||
|
line-height 1.3
|
||||||
|
color lighten($textColor, 40%)
|
||||||
|
.action-button
|
||||||
|
display inline-block
|
||||||
|
font-size 1.2rem
|
||||||
|
color #fff
|
||||||
|
background-color $accentColor
|
||||||
|
padding 0.8rem 1.6rem
|
||||||
|
border-radius 4px
|
||||||
|
transition background-color .1s ease
|
||||||
|
box-sizing border-box
|
||||||
|
border-bottom 1px solid darken($accentColor, 10%)
|
||||||
|
&:hover
|
||||||
|
background-color lighten($accentColor, 10%)
|
||||||
|
.features
|
||||||
|
border-top 1px solid $borderColor
|
||||||
|
padding 1.2rem 0
|
||||||
|
margin-top 2.5rem
|
||||||
|
display flex
|
||||||
|
flex-wrap wrap
|
||||||
|
align-items flex-start
|
||||||
|
align-content stretch
|
||||||
|
justify-content space-between
|
||||||
|
.feature
|
||||||
|
flex-grow 1
|
||||||
|
flex-basis 30%
|
||||||
|
max-width 30%
|
||||||
|
h2
|
||||||
|
font-size 1.4rem
|
||||||
|
font-weight 500
|
||||||
|
border-bottom none
|
||||||
|
padding-bottom 0
|
||||||
|
color lighten($textColor, 10%)
|
||||||
|
p
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
.footer
|
||||||
|
padding 2.5rem
|
||||||
|
border-top 1px solid $borderColor
|
||||||
|
text-align center
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.home
|
||||||
|
.features
|
||||||
|
flex-direction column
|
||||||
|
.feature
|
||||||
|
max-width 100%
|
||||||
|
padding 0 2.5rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobileNarrow)
|
||||||
|
.home
|
||||||
|
padding-left 1.5rem
|
||||||
|
padding-right 1.5rem
|
||||||
|
.hero
|
||||||
|
img
|
||||||
|
max-height 210px
|
||||||
|
margin 2rem auto 1.2rem
|
||||||
|
h1
|
||||||
|
font-size 2rem
|
||||||
|
h1, .description, .action
|
||||||
|
margin 1.2rem auto
|
||||||
|
.description
|
||||||
|
font-size 1.2rem
|
||||||
|
.action-button
|
||||||
|
font-size 1rem
|
||||||
|
padding 0.6rem 1.2rem
|
||||||
|
.feature
|
||||||
|
h2
|
||||||
|
font-size 1.25rem
|
||||||
|
</style>
|
183
ui/src/vuepress/Layout.vue
Normal file
183
ui/src/vuepress/Layout.vue
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="theme-container"
|
||||||
|
:class="pageClasses"
|
||||||
|
@touchstart="onTouchStart"
|
||||||
|
@touchend="onTouchEnd"
|
||||||
|
>
|
||||||
|
<Navbar
|
||||||
|
v-if="shouldShowNavbar"
|
||||||
|
@toggle-sidebar="toggleSidebar"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="sidebar-mask"
|
||||||
|
@click="toggleSidebar(false)"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<Sidebar
|
||||||
|
:items="sidebarItems"
|
||||||
|
@toggle-sidebar="toggleSidebar"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="sidebar-top"
|
||||||
|
slot="top"
|
||||||
|
/>
|
||||||
|
<slot
|
||||||
|
name="sidebar-bottom"
|
||||||
|
slot="bottom"
|
||||||
|
/>
|
||||||
|
</Sidebar>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="custom-layout"
|
||||||
|
v-if="$page.frontmatter.layout"
|
||||||
|
>
|
||||||
|
<component :is="$page.frontmatter.layout"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Home v-else-if="$page.frontmatter.home"/>
|
||||||
|
|
||||||
|
<Page
|
||||||
|
v-else
|
||||||
|
:sidebar-items="sidebarItems"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
name="page-top"
|
||||||
|
slot="top"
|
||||||
|
/>
|
||||||
|
<slot
|
||||||
|
name="page-bottom"
|
||||||
|
slot="bottom"
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
|
|
||||||
|
<SWUpdatePopup :updateEvent="swUpdateEvent"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Vue from 'vue'
|
||||||
|
import nprogress from 'nprogress'
|
||||||
|
import Home from './Home.vue'
|
||||||
|
import Navbar from './Navbar.vue'
|
||||||
|
import Page from './Page.vue'
|
||||||
|
import Sidebar from './Sidebar.vue'
|
||||||
|
import SWUpdatePopup from './SWUpdatePopup.vue'
|
||||||
|
import { resolveSidebarItems } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { Home, Page, Sidebar, Navbar, SWUpdatePopup },
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
isSidebarOpen: false,
|
||||||
|
swUpdateEvent: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
shouldShowNavbar () {
|
||||||
|
const { themeConfig } = this.$site
|
||||||
|
const { frontmatter } = this.$page
|
||||||
|
if (
|
||||||
|
frontmatter.navbar === false ||
|
||||||
|
themeConfig.navbar === false) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
this.$title ||
|
||||||
|
themeConfig.logo ||
|
||||||
|
themeConfig.repo ||
|
||||||
|
themeConfig.nav ||
|
||||||
|
this.$themeLocaleConfig.nav
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldShowSidebar () {
|
||||||
|
const { frontmatter } = this.$page
|
||||||
|
return (
|
||||||
|
!frontmatter.layout &&
|
||||||
|
!frontmatter.home &&
|
||||||
|
frontmatter.sidebar !== false &&
|
||||||
|
this.sidebarItems.length
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
sidebarItems () {
|
||||||
|
return resolveSidebarItems(
|
||||||
|
this.$page,
|
||||||
|
this.$route,
|
||||||
|
this.$site,
|
||||||
|
this.$localePath
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
pageClasses () {
|
||||||
|
const userPageClass = this.$page.frontmatter.pageClass
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'no-navbar': !this.shouldShowNavbar,
|
||||||
|
'sidebar-open': this.isSidebarOpen,
|
||||||
|
'no-sidebar': !this.shouldShowSidebar
|
||||||
|
},
|
||||||
|
userPageClass
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
window.addEventListener('scroll', this.onScroll)
|
||||||
|
|
||||||
|
// configure progress bar
|
||||||
|
nprogress.configure({ showSpinner: false })
|
||||||
|
|
||||||
|
this.$router.beforeEach((to, from, next) => {
|
||||||
|
if (to.path !== from.path && !Vue.component(to.name)) {
|
||||||
|
nprogress.start()
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$router.afterEach(() => {
|
||||||
|
nprogress.done()
|
||||||
|
this.isSidebarOpen = false
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$on('sw-updated', this.onSWUpdated)
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
toggleSidebar (to) {
|
||||||
|
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
|
||||||
|
},
|
||||||
|
|
||||||
|
// side swipe
|
||||||
|
onTouchStart (e) {
|
||||||
|
this.touchStart = {
|
||||||
|
x: e.changedTouches[0].clientX,
|
||||||
|
y: e.changedTouches[0].clientY
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onTouchEnd (e) {
|
||||||
|
const dx = e.changedTouches[0].clientX - this.touchStart.x
|
||||||
|
const dy = e.changedTouches[0].clientY - this.touchStart.y
|
||||||
|
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||||||
|
if (dx > 0 && this.touchStart.x <= 80) {
|
||||||
|
this.toggleSidebar(true)
|
||||||
|
} else {
|
||||||
|
this.toggleSidebar(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onSWUpdated (e) {
|
||||||
|
this.swUpdateEvent = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style src="prismjs/themes/prism-tomorrow.css"></style>
|
||||||
|
<style src="./styles/theme.styl" lang="stylus"></style>
|
49
ui/src/vuepress/NavLink.vue
Normal file
49
ui/src/vuepress/NavLink.vue
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<template>
|
||||||
|
<router-link
|
||||||
|
class="nav-link"
|
||||||
|
:to="link"
|
||||||
|
v-if="!isExternal(link)"
|
||||||
|
:exact="exact"
|
||||||
|
>{{ item.text }}</router-link>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
:href="link"
|
||||||
|
class="nav-link external"
|
||||||
|
:target="isMailto(link) || isTel(link) ? null : '_blank'"
|
||||||
|
:rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
|
<OutboundLink/>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isExternal, isMailto, isTel, ensureExt } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
link () {
|
||||||
|
return ensureExt(this.item.link)
|
||||||
|
},
|
||||||
|
|
||||||
|
exact () {
|
||||||
|
if (this.$site.locales) {
|
||||||
|
return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
|
||||||
|
}
|
||||||
|
return this.link === '/'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
isExternal,
|
||||||
|
isMailto,
|
||||||
|
isTel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
149
ui/src/vuepress/NavLinks.vue
Normal file
149
ui/src/vuepress/NavLinks.vue
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
<template>
|
||||||
|
<nav
|
||||||
|
class="nav-links"
|
||||||
|
v-if="userLinks.length || repoLink"
|
||||||
|
>
|
||||||
|
<!-- user links -->
|
||||||
|
<div
|
||||||
|
class="nav-item"
|
||||||
|
v-for="item in userLinks"
|
||||||
|
:key="item.link"
|
||||||
|
>
|
||||||
|
<DropdownLink
|
||||||
|
v-if="item.type === 'links'"
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
|
<NavLink
|
||||||
|
v-else
|
||||||
|
:item="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- repo link -->
|
||||||
|
<a
|
||||||
|
v-if="repoLink"
|
||||||
|
:href="repoLink"
|
||||||
|
class="repo-link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{{ repoLabel }}
|
||||||
|
<OutboundLink/>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DropdownLink from './DropdownLink.vue'
|
||||||
|
import { resolveNavLinkItem } from './util'
|
||||||
|
import NavLink from './NavLink.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { NavLink, DropdownLink },
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
userNav () {
|
||||||
|
return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
|
||||||
|
},
|
||||||
|
|
||||||
|
nav () {
|
||||||
|
const { locales } = this.$site
|
||||||
|
if (locales && Object.keys(locales).length > 1) {
|
||||||
|
const currentLink = this.$page.path
|
||||||
|
const routes = this.$router.options.routes
|
||||||
|
const themeLocales = this.$site.themeConfig.locales || {}
|
||||||
|
const languageDropdown = {
|
||||||
|
text: this.$themeLocaleConfig.selectText || 'Languages',
|
||||||
|
items: Object.keys(locales).map(path => {
|
||||||
|
const locale = locales[path]
|
||||||
|
const text = themeLocales[path] && themeLocales[path].label || locale.lang
|
||||||
|
let link
|
||||||
|
// Stay on the current page
|
||||||
|
if (locale.lang === this.$lang) {
|
||||||
|
link = currentLink
|
||||||
|
} else {
|
||||||
|
// Try to stay on the same page
|
||||||
|
link = currentLink.replace(this.$localeConfig.path, path)
|
||||||
|
// fallback to homepage
|
||||||
|
if (!routes.some(route => route.path === link)) {
|
||||||
|
link = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { text, link }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return [...this.userNav, languageDropdown]
|
||||||
|
}
|
||||||
|
return this.userNav
|
||||||
|
},
|
||||||
|
|
||||||
|
userLinks () {
|
||||||
|
return (this.nav || []).map(link => {
|
||||||
|
return Object.assign(resolveNavLinkItem(link), {
|
||||||
|
items: (link.items || []).map(resolveNavLinkItem)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
repoLink () {
|
||||||
|
const { repo } = this.$site.themeConfig
|
||||||
|
if (repo) {
|
||||||
|
return /^https?:/.test(repo)
|
||||||
|
? repo
|
||||||
|
: `https://github.com/${repo}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
repoLabel () {
|
||||||
|
if (!this.repoLink) return
|
||||||
|
if (this.$site.themeConfig.repoLabel) {
|
||||||
|
return this.$site.themeConfig.repoLabel
|
||||||
|
}
|
||||||
|
|
||||||
|
const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
|
||||||
|
const platforms = ['GitHub', 'GitLab', 'Bitbucket']
|
||||||
|
for (let i = 0; i < platforms.length; i++) {
|
||||||
|
const platform = platforms[i]
|
||||||
|
if (new RegExp(platform, 'i').test(repoHost)) {
|
||||||
|
return platform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Source'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.nav-links
|
||||||
|
display inline-block
|
||||||
|
a
|
||||||
|
line-height 1.4rem
|
||||||
|
color inherit
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
color $accentColor
|
||||||
|
.nav-item
|
||||||
|
position relative
|
||||||
|
display inline-block
|
||||||
|
margin-left 1.5rem
|
||||||
|
line-height 2rem
|
||||||
|
.repo-link
|
||||||
|
margin-left 1.5rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.nav-links
|
||||||
|
.nav-item, .repo-link
|
||||||
|
margin-left 0
|
||||||
|
|
||||||
|
@media (min-width: $MQMobile)
|
||||||
|
.nav-links a
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
color $textColor
|
||||||
|
.nav-item > a:not(.external)
|
||||||
|
&:hover, &.router-link-active
|
||||||
|
margin-bottom -2px
|
||||||
|
border-bottom 2px solid lighten($accentColor, 8%)
|
||||||
|
</style>
|
84
ui/src/vuepress/Navbar.vue
Normal file
84
ui/src/vuepress/Navbar.vue
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<template>
|
||||||
|
<header class="navbar">
|
||||||
|
<SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
|
||||||
|
|
||||||
|
<router-link
|
||||||
|
:to="$localePath"
|
||||||
|
class="home-link"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="logo"
|
||||||
|
v-if="$site.themeConfig.logo"
|
||||||
|
:src="$withBase($site.themeConfig.logo)"
|
||||||
|
:alt="$siteTitle"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="site-name"
|
||||||
|
v-if="$siteTitle"
|
||||||
|
:class="{ 'can-hide': $site.themeConfig.logo }"
|
||||||
|
>{{ $siteTitle }}</span>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
|
<div class="links">
|
||||||
|
<AlgoliaSearchBox
|
||||||
|
v-if="isAlgoliaSearch"
|
||||||
|
:options="algolia"
|
||||||
|
/>
|
||||||
|
<SearchBox v-else-if="$site.themeConfig.search !== false"/>
|
||||||
|
<NavLinks class="can-hide"/>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SidebarButton from './SidebarButton.vue'
|
||||||
|
import AlgoliaSearchBox from '@AlgoliaSearchBox'
|
||||||
|
import SearchBox from './SearchBox.vue'
|
||||||
|
import NavLinks from './NavLinks.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox },
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
algolia () {
|
||||||
|
return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
|
||||||
|
},
|
||||||
|
|
||||||
|
isAlgoliaSearch () {
|
||||||
|
return this.algolia && this.algolia.apiKey && this.algolia.indexName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.navbar
|
||||||
|
padding 0.7rem 1.5rem
|
||||||
|
line-height $navbarHeight - 1.4rem
|
||||||
|
position relative
|
||||||
|
a, span, img
|
||||||
|
display inline-block
|
||||||
|
.logo
|
||||||
|
height $navbarHeight - 1.4rem
|
||||||
|
min-width $navbarHeight - 1.4rem
|
||||||
|
margin-right 0.8rem
|
||||||
|
vertical-align top
|
||||||
|
.site-name
|
||||||
|
font-size 1.3rem
|
||||||
|
font-weight 600
|
||||||
|
color $textColor
|
||||||
|
position relative
|
||||||
|
.links
|
||||||
|
font-size 0.9rem
|
||||||
|
position absolute
|
||||||
|
right 1.5rem
|
||||||
|
top 0.7rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.navbar
|
||||||
|
padding-left 4rem
|
||||||
|
.can-hide
|
||||||
|
display none
|
||||||
|
</style>
|
26
ui/src/vuepress/NotFound.vue
Normal file
26
ui/src/vuepress/NotFound.vue
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<div class="theme-container">
|
||||||
|
<div class="content">
|
||||||
|
<h1>404</h1>
|
||||||
|
<blockquote>{{ getMsg() }}</blockquote>
|
||||||
|
<router-link to="/">Take me home.</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const msgs = [
|
||||||
|
`There's nothing here.`,
|
||||||
|
`How did we get here?`,
|
||||||
|
`That's a Four-Oh-Four.`,
|
||||||
|
`Looks like we've got some broken links.`
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
getMsg () {
|
||||||
|
return msgs[Math.floor(Math.random() * msgs.length)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
246
ui/src/vuepress/Page.vue
Normal file
246
ui/src/vuepress/Page.vue
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
<template>
|
||||||
|
<div class="page">
|
||||||
|
<slot name="top"/>
|
||||||
|
|
||||||
|
<Content :custom="false"/>
|
||||||
|
|
||||||
|
<div class="page-edit">
|
||||||
|
<div
|
||||||
|
class="edit-link"
|
||||||
|
v-if="editLink"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
:href="editLink"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>{{ editLinkText }}</a>
|
||||||
|
<OutboundLink/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="last-updated"
|
||||||
|
v-if="lastUpdated"
|
||||||
|
>
|
||||||
|
<span class="prefix">{{ lastUpdatedText }}: </span>
|
||||||
|
<span class="time">{{ lastUpdated }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-nav" v-if="prev || next">
|
||||||
|
<p class="inner">
|
||||||
|
<span
|
||||||
|
v-if="prev"
|
||||||
|
class="prev"
|
||||||
|
>
|
||||||
|
←
|
||||||
|
<router-link
|
||||||
|
v-if="prev"
|
||||||
|
class="prev"
|
||||||
|
:to="prev.path"
|
||||||
|
>
|
||||||
|
{{ prev.title || prev.path }}
|
||||||
|
</router-link>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-if="next"
|
||||||
|
class="next"
|
||||||
|
>
|
||||||
|
<router-link
|
||||||
|
v-if="next"
|
||||||
|
:to="next.path"
|
||||||
|
>
|
||||||
|
{{ next.title || next.path }}
|
||||||
|
</router-link>
|
||||||
|
→
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot name="bottom"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { resolvePage, normalize, outboundRE, endingSlashRE } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: ['sidebarItems'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
lastUpdated () {
|
||||||
|
if (this.$page.lastUpdated) {
|
||||||
|
return new Date(this.$page.lastUpdated).toLocaleString(this.$lang)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lastUpdatedText () {
|
||||||
|
if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
|
||||||
|
return this.$themeLocaleConfig.lastUpdated
|
||||||
|
}
|
||||||
|
if (typeof this.$site.themeConfig.lastUpdated === 'string') {
|
||||||
|
return this.$site.themeConfig.lastUpdated
|
||||||
|
}
|
||||||
|
return 'Last Updated'
|
||||||
|
},
|
||||||
|
|
||||||
|
prev () {
|
||||||
|
const prev = this.$page.frontmatter.prev
|
||||||
|
if (prev === false) {
|
||||||
|
return
|
||||||
|
} else if (prev) {
|
||||||
|
return resolvePage(this.$site.pages, prev, this.$route.path)
|
||||||
|
} else {
|
||||||
|
return resolvePrev(this.$page, this.sidebarItems)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
next () {
|
||||||
|
const next = this.$page.frontmatter.next
|
||||||
|
if (next === false) {
|
||||||
|
return
|
||||||
|
} else if (next) {
|
||||||
|
return resolvePage(this.$site.pages, next, this.$route.path)
|
||||||
|
} else {
|
||||||
|
return resolveNext(this.$page, this.sidebarItems)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
editLink () {
|
||||||
|
if (this.$page.frontmatter.editLink === false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
repo,
|
||||||
|
editLinks,
|
||||||
|
docsDir = '',
|
||||||
|
docsBranch = 'master',
|
||||||
|
docsRepo = repo
|
||||||
|
} = this.$site.themeConfig
|
||||||
|
|
||||||
|
let path = normalize(this.$page.path)
|
||||||
|
if (endingSlashRE.test(path)) {
|
||||||
|
path += 'README.md'
|
||||||
|
} else {
|
||||||
|
path += '.md'
|
||||||
|
}
|
||||||
|
if (docsRepo && editLinks) {
|
||||||
|
return this.createEditLink(repo, docsRepo, docsDir, docsBranch, path)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
editLinkText () {
|
||||||
|
return (
|
||||||
|
this.$themeLocaleConfig.editLinkText ||
|
||||||
|
this.$site.themeConfig.editLinkText ||
|
||||||
|
`Edit this page`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
|
||||||
|
const bitbucket = /bitbucket.org/
|
||||||
|
if (bitbucket.test(repo)) {
|
||||||
|
const base = outboundRE.test(docsRepo)
|
||||||
|
? docsRepo
|
||||||
|
: repo
|
||||||
|
return (
|
||||||
|
base.replace(endingSlashRE, '') +
|
||||||
|
`/${docsBranch}` +
|
||||||
|
(docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
|
||||||
|
path +
|
||||||
|
`?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = outboundRE.test(docsRepo)
|
||||||
|
? docsRepo
|
||||||
|
: `https://github.com/${docsRepo}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
base.replace(endingSlashRE, '') +
|
||||||
|
`/edit/${docsBranch}` +
|
||||||
|
(docsDir ? '/' + docsDir.replace(endingSlashRE, '') : '') +
|
||||||
|
path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePrev (page, items) {
|
||||||
|
return find(page, items, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveNext (page, items) {
|
||||||
|
return find(page, items, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function find (page, items, offset) {
|
||||||
|
const res = []
|
||||||
|
items.forEach(item => {
|
||||||
|
if (item.type === 'group') {
|
||||||
|
res.push(...item.children || [])
|
||||||
|
} else {
|
||||||
|
res.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
const cur = res[i]
|
||||||
|
if (cur.type === 'page' && cur.path === page.path) {
|
||||||
|
return res[i + offset]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
@require './styles/wrapper.styl'
|
||||||
|
|
||||||
|
.page
|
||||||
|
padding-bottom 2rem
|
||||||
|
|
||||||
|
.page-edit
|
||||||
|
@extend $wrapper
|
||||||
|
padding-top 1rem
|
||||||
|
padding-bottom 1rem
|
||||||
|
overflow auto
|
||||||
|
.edit-link
|
||||||
|
display inline-block
|
||||||
|
a
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
margin-right 0.25rem
|
||||||
|
.last-updated
|
||||||
|
float right
|
||||||
|
font-size 0.9em
|
||||||
|
.prefix
|
||||||
|
font-weight 500
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
.time
|
||||||
|
font-weight 400
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
.page-nav
|
||||||
|
@extend $wrapper
|
||||||
|
padding-top 1rem
|
||||||
|
padding-bottom 0
|
||||||
|
.inner
|
||||||
|
min-height 2rem
|
||||||
|
margin-top 0
|
||||||
|
border-top 1px solid $borderColor
|
||||||
|
padding-top 1rem
|
||||||
|
overflow auto // clear float
|
||||||
|
.next
|
||||||
|
float right
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.page-edit
|
||||||
|
.edit-link
|
||||||
|
margin-bottom .5rem
|
||||||
|
.last-updated
|
||||||
|
font-size .8em
|
||||||
|
float none
|
||||||
|
text-align left
|
||||||
|
|
||||||
|
</style>
|
4
ui/src/vuepress/README.txt
Normal file
4
ui/src/vuepress/README.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
vuepress folder contains the theme from VuePress 0.13.0.
|
||||||
|
Generated by creating a sample VuePress site and calling `vuepress eject`.
|
||||||
|
This is kept here as reference do not modify it unless you upgrading the theme!
|
||||||
|
Styles are used directly while vue components are kept only for reference.
|
85
ui/src/vuepress/SWUpdatePopup.vue
Normal file
85
ui/src/vuepress/SWUpdatePopup.vue
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
<template>
|
||||||
|
<transition name="sw-update-popup">
|
||||||
|
<div
|
||||||
|
v-if="enabled"
|
||||||
|
class="sw-update-popup"
|
||||||
|
>
|
||||||
|
{{message}}<br>
|
||||||
|
<button @click="reload">{{buttonText}}</button>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
updateEvent: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
popupConfig () {
|
||||||
|
for (const config of [this.$themeLocaleConfig, this.$site.themeConfig]) {
|
||||||
|
const sw = config.serviceWorker
|
||||||
|
if (sw && sw.updatePopup) {
|
||||||
|
return typeof sw.updatePopup === 'object' ? sw.updatePopup : {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
|
enabled () {
|
||||||
|
return Boolean(this.popupConfig && this.updateEvent)
|
||||||
|
},
|
||||||
|
|
||||||
|
message () {
|
||||||
|
const c = this.popupConfig
|
||||||
|
return (c && c.message) || 'New content is available.'
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonText () {
|
||||||
|
const c = this.popupConfig
|
||||||
|
return (c && c.buttonText) || 'Refresh'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
reload () {
|
||||||
|
if (this.updateEvent) {
|
||||||
|
this.updateEvent.skipWaiting().then(() => {
|
||||||
|
location.reload(true)
|
||||||
|
})
|
||||||
|
this.updateEvent = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.sw-update-popup
|
||||||
|
position fixed
|
||||||
|
right 1em
|
||||||
|
bottom 1em
|
||||||
|
padding 1em
|
||||||
|
border 1px solid $accentColor
|
||||||
|
border-radius 3px
|
||||||
|
background #fff
|
||||||
|
box-shadow 0 4px 16px rgba(0, 0, 0, 0.5)
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
button
|
||||||
|
margin-top 0.5em
|
||||||
|
padding 0.25em 2em
|
||||||
|
|
||||||
|
.sw-update-popup-enter-active, .sw-update-popup-leave-active
|
||||||
|
transition opacity 0.3s, transform 0.3s
|
||||||
|
|
||||||
|
.sw-update-popup-enter, .sw-update-popup-leave-to
|
||||||
|
opacity 0
|
||||||
|
transform translate(0, 50%) scale(0.5)
|
||||||
|
</style>
|
235
ui/src/vuepress/SearchBox.vue
Normal file
235
ui/src/vuepress/SearchBox.vue
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
<template>
|
||||||
|
<div class="search-box">
|
||||||
|
<input
|
||||||
|
@input="query = $event.target.value"
|
||||||
|
aria-label="Search"
|
||||||
|
:value="query"
|
||||||
|
autocomplete="off"
|
||||||
|
spellcheck="false"
|
||||||
|
@focus="focused = true"
|
||||||
|
@blur="focused = false"
|
||||||
|
@keyup.enter="go(focusIndex)"
|
||||||
|
@keyup.up="onUp"
|
||||||
|
@keyup.down="onDown"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="suggestions"
|
||||||
|
v-if="showSuggestions"
|
||||||
|
:class="{ 'align-right': alignRight }"
|
||||||
|
@mouseleave="unfocus"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="suggestion"
|
||||||
|
v-for="(s, i) in suggestions"
|
||||||
|
:class="{ focused: i === focusIndex }"
|
||||||
|
@mousedown="go(i)"
|
||||||
|
@mouseenter="focus(i)"
|
||||||
|
>
|
||||||
|
<a :href="s.path" @click.prevent>
|
||||||
|
<span class="page-title">{{ s.title || s.path }}</span>
|
||||||
|
<span v-if="s.header" class="header">> {{ s.header.title }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
query: '',
|
||||||
|
focused: false,
|
||||||
|
focusIndex: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
showSuggestions () {
|
||||||
|
return (
|
||||||
|
this.focused &&
|
||||||
|
this.suggestions &&
|
||||||
|
this.suggestions.length
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
suggestions () {
|
||||||
|
const query = this.query.trim().toLowerCase()
|
||||||
|
if (!query) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { pages, themeConfig } = this.$site
|
||||||
|
const max = themeConfig.searchMaxSuggestions || 5
|
||||||
|
const localePath = this.$localePath
|
||||||
|
const matches = item => (
|
||||||
|
item.title &&
|
||||||
|
item.title.toLowerCase().indexOf(query) > -1
|
||||||
|
)
|
||||||
|
const res = []
|
||||||
|
for (let i = 0; i < pages.length; i++) {
|
||||||
|
if (res.length >= max) break
|
||||||
|
const p = pages[i]
|
||||||
|
// filter out results that do not match current locale
|
||||||
|
if (this.getPageLocalePath(p) !== localePath) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (matches(p)) {
|
||||||
|
res.push(p)
|
||||||
|
} else if (p.headers) {
|
||||||
|
for (let j = 0; j < p.headers.length; j++) {
|
||||||
|
if (res.length >= max) break
|
||||||
|
const h = p.headers[j]
|
||||||
|
if (matches(h)) {
|
||||||
|
res.push(Object.assign({}, p, {
|
||||||
|
path: p.path + '#' + h.slug,
|
||||||
|
header: h
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
|
// make suggestions align right when there are not enough items
|
||||||
|
alignRight () {
|
||||||
|
const navCount = (this.$site.themeConfig.nav || []).length
|
||||||
|
const repo = this.$site.repo ? 1 : 0
|
||||||
|
return navCount + repo <= 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getPageLocalePath (page) {
|
||||||
|
for (const localePath in this.$site.locales || {}) {
|
||||||
|
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
|
||||||
|
return localePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '/'
|
||||||
|
},
|
||||||
|
|
||||||
|
onUp () {
|
||||||
|
if (this.showSuggestions) {
|
||||||
|
if (this.focusIndex > 0) {
|
||||||
|
this.focusIndex--
|
||||||
|
} else {
|
||||||
|
this.focusIndex = this.suggestions.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onDown () {
|
||||||
|
if (this.showSuggestions) {
|
||||||
|
if (this.focusIndex < this.suggestions.length - 1) {
|
||||||
|
this.focusIndex++
|
||||||
|
} else {
|
||||||
|
this.focusIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
go (i) {
|
||||||
|
if (!this.showSuggestions) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$router.push(this.suggestions[i].path)
|
||||||
|
this.query = ''
|
||||||
|
this.focusIndex = 0
|
||||||
|
},
|
||||||
|
|
||||||
|
focus (i) {
|
||||||
|
this.focusIndex = i
|
||||||
|
},
|
||||||
|
|
||||||
|
unfocus () {
|
||||||
|
this.focusIndex = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.search-box
|
||||||
|
display inline-block
|
||||||
|
position relative
|
||||||
|
margin-right 0.5rem
|
||||||
|
input
|
||||||
|
cursor text
|
||||||
|
width 10rem
|
||||||
|
color lighten($textColor, 25%)
|
||||||
|
display inline-block
|
||||||
|
border 1px solid darken($borderColor, 10%)
|
||||||
|
border-radius 2rem
|
||||||
|
font-size 0.9rem
|
||||||
|
line-height 2rem
|
||||||
|
padding 0 0.5rem 0 2rem
|
||||||
|
outline none
|
||||||
|
transition all .2s ease
|
||||||
|
background #fff url(./search.svg) 0.6rem 0.5rem no-repeat
|
||||||
|
background-size 1rem
|
||||||
|
&:focus
|
||||||
|
cursor auto
|
||||||
|
border-color $accentColor
|
||||||
|
.suggestions
|
||||||
|
background #fff
|
||||||
|
width 20rem
|
||||||
|
position absolute
|
||||||
|
top 1.5rem
|
||||||
|
border 1px solid darken($borderColor, 10%)
|
||||||
|
border-radius 6px
|
||||||
|
padding 0.4rem
|
||||||
|
list-style-type none
|
||||||
|
&.align-right
|
||||||
|
right 0
|
||||||
|
.suggestion
|
||||||
|
line-height 1.4
|
||||||
|
padding 0.4rem 0.6rem
|
||||||
|
border-radius 4px
|
||||||
|
cursor pointer
|
||||||
|
a
|
||||||
|
color lighten($textColor, 35%)
|
||||||
|
.page-title
|
||||||
|
font-weight 600
|
||||||
|
.header
|
||||||
|
font-size 0.9em
|
||||||
|
margin-left 0.25em
|
||||||
|
&.focused
|
||||||
|
background-color #f3f4f5
|
||||||
|
a
|
||||||
|
color $accentColor
|
||||||
|
|
||||||
|
@media (max-width: $MQNarrow)
|
||||||
|
.search-box
|
||||||
|
input
|
||||||
|
cursor pointer
|
||||||
|
width 0
|
||||||
|
border-color transparent
|
||||||
|
position relative
|
||||||
|
left 1rem
|
||||||
|
&:focus
|
||||||
|
cursor text
|
||||||
|
left 0
|
||||||
|
width 10rem
|
||||||
|
|
||||||
|
@media (max-width: $MQNarrow) and (min-width: $MQMobile)
|
||||||
|
.search-box
|
||||||
|
.suggestions
|
||||||
|
left 0
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.search-box
|
||||||
|
margin-right 0
|
||||||
|
.suggestions
|
||||||
|
right 0
|
||||||
|
|
||||||
|
@media (max-width: $MQMobileNarrow)
|
||||||
|
.search-box
|
||||||
|
.suggestions
|
||||||
|
width calc(100vw - 4rem)
|
||||||
|
input:focus
|
||||||
|
width 8rem
|
||||||
|
</style>
|
113
ui/src/vuepress/Sidebar.vue
Normal file
113
ui/src/vuepress/Sidebar.vue
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
<template>
|
||||||
|
<div class="sidebar">
|
||||||
|
<NavLinks/>
|
||||||
|
<slot name="top"/>
|
||||||
|
<ul class="sidebar-links" v-if="items.length">
|
||||||
|
<li v-for="(item, i) in items" :key="i">
|
||||||
|
<SidebarGroup
|
||||||
|
v-if="item.type === 'group'"
|
||||||
|
:item="item"
|
||||||
|
:first="i === 0"
|
||||||
|
:open="i === openGroupIndex"
|
||||||
|
:collapsable="item.collapsable"
|
||||||
|
@toggle="toggleGroup(i)"
|
||||||
|
/>
|
||||||
|
<SidebarLink v-else :item="item"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<slot name="bottom"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SidebarGroup from './SidebarGroup.vue'
|
||||||
|
import SidebarLink from './SidebarLink.vue'
|
||||||
|
import NavLinks from './NavLinks.vue'
|
||||||
|
import { isActive } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { SidebarGroup, SidebarLink, NavLinks },
|
||||||
|
|
||||||
|
props: ['items'],
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
openGroupIndex: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.refreshIndex()
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
'$route' () {
|
||||||
|
this.refreshIndex()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
refreshIndex () {
|
||||||
|
const index = resolveOpenGroupIndex(
|
||||||
|
this.$route,
|
||||||
|
this.items
|
||||||
|
)
|
||||||
|
if (index > -1) {
|
||||||
|
this.openGroupIndex = index
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleGroup (index) {
|
||||||
|
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
|
||||||
|
},
|
||||||
|
|
||||||
|
isActive (page) {
|
||||||
|
return isActive(this.$route, page.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveOpenGroupIndex (route, items) {
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i]
|
||||||
|
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.sidebar
|
||||||
|
ul
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
list-style-type none
|
||||||
|
a
|
||||||
|
display inline-block
|
||||||
|
.nav-links
|
||||||
|
display none
|
||||||
|
border-bottom 1px solid $borderColor
|
||||||
|
padding 0.5rem 0 0.75rem 0
|
||||||
|
a
|
||||||
|
font-weight 600
|
||||||
|
.nav-item, .repo-link
|
||||||
|
display block
|
||||||
|
line-height 1.25rem
|
||||||
|
font-size 1.1em
|
||||||
|
padding 0.5rem 0 0.5rem 1.5rem
|
||||||
|
.sidebar-links
|
||||||
|
padding 1.5rem 0
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.sidebar
|
||||||
|
.nav-links
|
||||||
|
display block
|
||||||
|
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||||
|
top calc(1rem - 2px)
|
||||||
|
.sidebar-links
|
||||||
|
padding 1rem 0
|
||||||
|
</style>
|
28
ui/src/vuepress/SidebarButton.vue
Normal file
28
ui/src/vuepress/SidebarButton.vue
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<template>
|
||||||
|
<div class="sidebar-button" @click="$emit('toggle-sidebar')">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512">
|
||||||
|
<path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" class=""></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.sidebar-button
|
||||||
|
display none
|
||||||
|
width 1.25rem
|
||||||
|
height 1.25rem
|
||||||
|
position absolute
|
||||||
|
padding 0.6rem
|
||||||
|
top 0.6rem
|
||||||
|
left 1rem
|
||||||
|
.icon
|
||||||
|
display block
|
||||||
|
width 1.25rem
|
||||||
|
height 1.25rem
|
||||||
|
|
||||||
|
@media (max-width: $MQMobile)
|
||||||
|
.sidebar-button
|
||||||
|
display block
|
||||||
|
</style>
|
77
ui/src/vuepress/SidebarGroup.vue
Normal file
77
ui/src/vuepress/SidebarGroup.vue
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="sidebar-group"
|
||||||
|
:class="{ first, collapsable }"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="sidebar-heading"
|
||||||
|
:class="{ open }"
|
||||||
|
@click="$emit('toggle')"
|
||||||
|
>
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<span
|
||||||
|
class="arrow"
|
||||||
|
v-if="collapsable"
|
||||||
|
:class="open ? 'down' : 'right'">
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<DropdownTransition>
|
||||||
|
<ul
|
||||||
|
ref="items"
|
||||||
|
class="sidebar-group-items"
|
||||||
|
v-if="open || !collapsable"
|
||||||
|
>
|
||||||
|
<li v-for="child in item.children">
|
||||||
|
<SidebarLink :item="child"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</DropdownTransition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SidebarLink from './SidebarLink.vue'
|
||||||
|
import DropdownTransition from './DropdownTransition.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SidebarGroup',
|
||||||
|
props: ['item', 'first', 'open', 'collapsable'],
|
||||||
|
components: { SidebarLink, DropdownTransition }
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
.sidebar-group
|
||||||
|
&:not(.first)
|
||||||
|
margin-top 1em
|
||||||
|
.sidebar-group
|
||||||
|
padding-left 0.5em
|
||||||
|
&:not(.collapsable)
|
||||||
|
.sidebar-heading
|
||||||
|
cursor auto
|
||||||
|
color inherit
|
||||||
|
|
||||||
|
.sidebar-heading
|
||||||
|
color #999
|
||||||
|
transition color .15s ease
|
||||||
|
cursor pointer
|
||||||
|
font-size 1.1em
|
||||||
|
font-weight bold
|
||||||
|
// text-transform uppercase
|
||||||
|
padding 0 1.5rem
|
||||||
|
margin-top 0
|
||||||
|
margin-bottom 0.5rem
|
||||||
|
&.open, &:hover
|
||||||
|
color inherit
|
||||||
|
.arrow
|
||||||
|
position relative
|
||||||
|
top -0.12em
|
||||||
|
left 0.5em
|
||||||
|
&:.open .arrow
|
||||||
|
top -0.18em
|
||||||
|
|
||||||
|
.sidebar-group-items
|
||||||
|
transition height .1s ease-out
|
||||||
|
overflow hidden
|
||||||
|
</style>
|
91
ui/src/vuepress/SidebarLink.vue
Normal file
91
ui/src/vuepress/SidebarLink.vue
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<script>
|
||||||
|
import { isActive, hashRE, groupHeaders } from './util'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
functional: true,
|
||||||
|
|
||||||
|
props: ['item'],
|
||||||
|
|
||||||
|
render (h, { parent: { $page, $site, $route }, props: { item }}) {
|
||||||
|
// use custom active class matching logic
|
||||||
|
// due to edge case of paths ending with / + hash
|
||||||
|
const selfActive = isActive($route, item.path)
|
||||||
|
// for sidebar: auto pages, a hash link should be active if one of its child
|
||||||
|
// matches
|
||||||
|
const active = item.type === 'auto'
|
||||||
|
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
|
||||||
|
: selfActive
|
||||||
|
const link = renderLink(h, item.path, item.title || item.path, active)
|
||||||
|
const configDepth = $page.frontmatter.sidebarDepth != null
|
||||||
|
? $page.frontmatter.sidebarDepth
|
||||||
|
: $site.themeConfig.sidebarDepth
|
||||||
|
const maxDepth = configDepth == null ? 1 : configDepth
|
||||||
|
const displayAllHeaders = !!$site.themeConfig.displayAllHeaders
|
||||||
|
if (item.type === 'auto') {
|
||||||
|
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
|
||||||
|
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
|
||||||
|
const children = groupHeaders(item.headers)
|
||||||
|
return [link, renderChildren(h, children, item.path, $route, maxDepth)]
|
||||||
|
} else {
|
||||||
|
return link
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderLink (h, to, text, active) {
|
||||||
|
return h('router-link', {
|
||||||
|
props: {
|
||||||
|
to,
|
||||||
|
activeClass: '',
|
||||||
|
exactActiveClass: ''
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
active,
|
||||||
|
'sidebar-link': true
|
||||||
|
}
|
||||||
|
}, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderChildren (h, children, path, route, maxDepth, depth = 1) {
|
||||||
|
if (!children || depth > maxDepth) return null
|
||||||
|
return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
|
||||||
|
const active = isActive(route, path + '#' + c.slug)
|
||||||
|
return h('li', { class: 'sidebar-sub-header' }, [
|
||||||
|
renderLink(h, path + '#' + c.slug, c.title, active),
|
||||||
|
renderChildren(h, c.children, path, route, maxDepth, depth + 1)
|
||||||
|
])
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus">
|
||||||
|
@import './styles/config.styl'
|
||||||
|
|
||||||
|
.sidebar .sidebar-sub-headers
|
||||||
|
padding-left 1rem
|
||||||
|
font-size 0.95em
|
||||||
|
|
||||||
|
a.sidebar-link
|
||||||
|
font-weight 400
|
||||||
|
display inline-block
|
||||||
|
color $textColor
|
||||||
|
border-left 0.25rem solid transparent
|
||||||
|
padding 0.35rem 1rem 0.35rem 1.25rem
|
||||||
|
line-height 1.4
|
||||||
|
width: 100%
|
||||||
|
box-sizing: border-box
|
||||||
|
&:hover
|
||||||
|
color $accentColor
|
||||||
|
&.active
|
||||||
|
font-weight 600
|
||||||
|
color $accentColor
|
||||||
|
border-left-color $accentColor
|
||||||
|
.sidebar-group &
|
||||||
|
padding-left 2rem
|
||||||
|
.sidebar-sub-headers &
|
||||||
|
padding-top 0.25rem
|
||||||
|
padding-bottom 0.25rem
|
||||||
|
border-left none
|
||||||
|
&.active
|
||||||
|
font-weight 500
|
||||||
|
</style>
|
1
ui/src/vuepress/search.svg
Normal file
1
ui/src/vuepress/search.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>
|
After Width: | Height: | Size: 216 B |
22
ui/src/vuepress/styles/arrow.styl
Normal file
22
ui/src/vuepress/styles/arrow.styl
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
@require './config'
|
||||||
|
|
||||||
|
.arrow
|
||||||
|
display inline-block
|
||||||
|
width 0
|
||||||
|
height 0
|
||||||
|
&.up
|
||||||
|
border-left 4px solid transparent
|
||||||
|
border-right 4px solid transparent
|
||||||
|
border-bottom 6px solid $arrowBgColor
|
||||||
|
&.down
|
||||||
|
border-left 4px solid transparent
|
||||||
|
border-right 4px solid transparent
|
||||||
|
border-top 6px solid $arrowBgColor
|
||||||
|
&.right
|
||||||
|
border-top 4px solid transparent
|
||||||
|
border-bottom 4px solid transparent
|
||||||
|
border-left 6px solid $arrowBgColor
|
||||||
|
&.left
|
||||||
|
border-top 4px solid transparent
|
||||||
|
border-bottom 4px solid transparent
|
||||||
|
border-right 6px solid $arrowBgColor
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue