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