diff --git a/template/docs/Makefile.jinja b/template/docs/Makefile.jinja
new file mode 100644
index 0000000..bdc6a11
--- /dev/null
+++ b/template/docs/Makefile.jinja
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = python -msphinx
+SPHINXPROJ = {{ project_slug }}
+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)
\ No newline at end of file
diff --git a/template/docs/api_reference.rst.jinja b/template/docs/api_reference.rst.jinja
new file mode 100644
index 0000000..73e9652
--- /dev/null
+++ b/template/docs/api_reference.rst.jinja
@@ -0,0 +1,22 @@
+.. _api_reference:
+
+API Reference
+=============
+
+The following gives detailed information about all {{ project_slug }} functions sorted
+according to their modules.
+
+For examples on how to use {{ project_slug }} refer to the notebooks in the
+`examples gallery`_ and the documentation on classes and modules below.
+
+
+Modules
+-------
+
+.. toctree::
+ :maxdepth: 1
+
+ modules/{{ project_slug }}
+
+
+.. _examples gallery: https://pyfar-gallery.readthedocs.io/en/latest/examples_gallery.html
\ No newline at end of file
diff --git a/template/docs/conf.py.jinja b/template/docs/conf.py.jinja
new file mode 100644
index 0000000..3cb867d
--- /dev/null
+++ b/template/docs/conf.py.jinja
@@ -0,0 +1,231 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+import os
+import sys
+import urllib3
+import shutil
+import numpy as np
+sys.path.insert(0, os.path.abspath('..'))
+
+import {{ project_slug }} # noqa
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'sphinx.ext.napoleon',
+ 'sphinx.ext.autosummary',
+ 'matplotlib.sphinxext.plot_directive',
+ 'sphinx.ext.mathjax',
+ 'sphinx.ext.intersphinx',
+ 'autodocsumm',
+ 'sphinx_design',
+ 'sphinx_favicon',
+ 'sphinx_reredirects',
+ 'sphinx_mdinclude',
+]
+
+# show tocs for classes and functions of modules using the autodocsumm
+# package
+autodoc_default_options = {'autosummary': True}
+
+# show the code of plots that follows the command .. plot:: based on the
+# package matplotlib.sphinxext.plot_directive
+plot_include_source = True
+
+# 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': 'restructuredtext',
+ '.md': 'markdown',
+}
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = '{{ project_slug }}'
+copyright = "{{ copyright_statement }}"
+author = "{{ author }}"
+
+# The version info for the project you're documenting, acts as replacement
+# for |version| and |release|, also used in various other places throughout
+# the built documents.
+#
+# The short X.Y version.
+version = {{ project_slug }}.__version__
+# The full version, including alpha/beta/rc tags.
+release = {{ project_slug }}.__version__
+
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = 'en'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The name of the Pygments (syntax highlighting) style to use (Not defining
+# uses the default style of the html_theme).
+# pygments_style = 'sphinx'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+# default language for highlighting in source code
+highlight_language = "python3"
+
+# intersphinx mapping
+intersphinx_mapping = {
+ {% if 'numpy' in dependencies -%}
+ 'numpy': ('https://numpy.org/doc/stable/', None),{% endif %}
+ {% if 'scipy' in dependencies -%}
+ 'scipy': ('https://docs.scipy.org/doc/scipy/', None),{% endif %}
+ {% if 'matplotlib' in dependencies -%}
+ 'matplotlib': ('https://matplotlib.org/stable/', None),{% endif %}
+ {% if 'pyfar' in dependencies -%}
+ 'pyfar': ('https://pyfar.readthedocs.io/en/stable/', None),{% endif %}
+ }
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = 'pydata_sphinx_theme'
+html_static_path = ['_static']
+html_css_files = ['css/custom.css']
+html_js_files = ['js/custom.js']
+html_logo = '{{ logo_path_gallery }}'
+html_title = "{{ project_slug }}"
+html_favicon = '_static/favicon.ico'
+
+# -- HTML theme options
+# https://pydata-sphinx-theme.readthedocs.io/en/stable/user_guide/layout.html
+html_sidebars = {
+ "{{ project_slug }}": []
+}
+
+html_theme_options = {
+ "navbar_start": ["navbar-logo"],
+ "navbar_end": ["navbar-icon-links", "theme-switcher"],
+ "navbar_align": "content",
+ "header_links_before_dropdown": None, # will be automatically set later based on headers.rst
+ "header_dropdown_text": "Packages", # Change dropdown name from "More" to "Packages"
+ "icon_links": [
+ {
+ "name": "GitHub",
+ "url": "https://github.com/pyfar",
+ "icon": "fa-brands fa-square-github",
+ "type": "fontawesome",
+ },
+ ],
+ # Configure secondary (right) side bar
+ "show_toc_level": 3, # Show all subsections of notebooks
+ "secondary_sidebar_items": ["page-toc"], # Omit 'show source' link that that shows notebook in json format
+ "navigation_with_keys": True,
+ # Configure navigation depth for section navigation
+ "navigation_depth": 2,
+}
+
+html_context = {
+ "default_mode": "light"
+}
+
+# redirect index to pyfar.html
+redirects = {
+ "index": "{{ project_slug }}.html"
+}
+
+# -- download navbar and style files from gallery -----------------------------
+branch = 'main'
+link = f'https://github.com/pyfar/gallery/raw/{branch}/docs/'
+folders_in = [
+ '_static/css/custom.css',
+ '_static/js/custom.js',
+ '_static/favicon.ico',
+ '_static/header.rst',
+ '{{ logo_path_gallery }}',
+ ]
+
+def download_files_from_gallery(link, folders_in):
+ c = urllib3.PoolManager()
+ for file in folders_in:
+ url = link + file
+ filename = file
+ os.makedirs(os.path.dirname(filename), exist_ok=True)
+ with c.request('GET', url, preload_content=False) as res:
+ if res.status == 200:
+ with open(filename, 'wb') as out_file:
+ shutil.copyfileobj(res, out_file)
+
+download_files_from_gallery(link, folders_in)
+# if logo does not exist, use pyfar logo
+if not os.path.exists(html_logo):
+ download_files_from_gallery(
+ link, ['resources/logos/pyfar_logos_fixed_size_pyfar.png'])
+ shutil.copyfile(
+ 'resources/logos/pyfar_logos_fixed_size_pyfar.png', html_logo)
+
+
+# -- modify downloaded header file from the gallery to ----------------------
+# -- aline with the local toctree ---------------------------------------------
+
+# read the header file from the gallery
+with open("_static/header.rst", "rt") as fin:
+ lines = [line for line in fin]
+
+# replace readthedocs link with internal link to this documentation
+lines_mod = [
+ line.replace(f'https://{project}.readthedocs.io', project) for line in lines]
+
+# if not found, add this documentation link to the end of the list, so that
+# it is in the doc tree
+contains_project = any(project in line for line in lines_mod)
+if not contains_project:
+ lines_mod.append(f' {project} <{project}>\n')
+
+# write the modified header file
+# to the doc\header.rst folder, so that it can be used in the documentation
+with open("header.rst", "wt") as fout:
+ fout.writelines(lines_mod)
+
+
+# -- find position of pyfar package in toctree --------------------------------
+# -- this is required to define the dropdown of Packages in the header --------
+
+# find line where pyfar package is mentioned, to determine the start of
+# the packages list in the header
+n_line_pyfar = 0
+for i, line in enumerate(lines):
+ if 'https://pyfar.readthedocs.io' in line:
+ n_line_pyfar = i
+ break
+
+# the first 4 lines of the header file are defining the settings and a empty
+# line of the toctree, therefore we need to subtract 4 from the line number
+# of the pyfar package to get the correct position in the toctree
+n_toctree_pyfar = n_line_pyfar - 4
+
+if n_toctree_pyfar < 1:
+ raise ValueError(
+ "Could not find the line where pyfar package is mentioned. "
+ "Please check the header.rst file in the gallery."
+ )
+
+# set dropdown header at pyfar appearance, so that pyfar is the first item in
+# the dropdown called Packages
+html_theme_options['header_links_before_dropdown'] = n_toctree_pyfar
\ No newline at end of file
diff --git a/template/docs/contributing.rst b/template/docs/contributing.rst
new file mode 100644
index 0000000..3bdd7dc
--- /dev/null
+++ b/template/docs/contributing.rst
@@ -0,0 +1 @@
+.. include:: ../CONTRIBUTING.rst
\ No newline at end of file
diff --git a/template/docs/history.rst b/template/docs/history.rst
new file mode 100644
index 0000000..bec23d8
--- /dev/null
+++ b/template/docs/history.rst
@@ -0,0 +1 @@
+.. include:: ../HISTORY.rst
\ No newline at end of file
diff --git a/template/docs/index.rst.jinja b/template/docs/index.rst.jinja
new file mode 100644
index 0000000..c7d7db9
--- /dev/null
+++ b/template/docs/index.rst.jinja
@@ -0,0 +1,4 @@
+{{ project_slug }}
+{% for _ in project_slug %}={% endfor %}
+
+.. include:: header.rst
\ No newline at end of file
diff --git a/template/docs/make.bat.jinja b/template/docs/make.bat.jinja
new file mode 100644
index 0000000..0ee37c7
--- /dev/null
+++ b/template/docs/make.bat.jinja
@@ -0,0 +1,36 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=python -msphinx
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+set SPHINXPROJ={{ project_slug }}
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The Sphinx module was not found. Make sure you have Sphinx installed,
+ echo.then set the SPHINXBUILD environment variable to point to the full
+ echo.path of the 'sphinx-build' executable. Alternatively you may add the
+ echo.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
\ No newline at end of file
diff --git a/template/docs/modules/{{ project_slug }}.rst.jinja b/template/docs/modules/{{ project_slug }}.rst.jinja
new file mode 100644
index 0000000..4447190
--- /dev/null
+++ b/template/docs/modules/{{ project_slug }}.rst.jinja
@@ -0,0 +1,7 @@
+{{ project_slug }}
+{% for _ in project_slug %}={% endfor %}
+
+.. automodule:: {{ project_slug }}
+ :members:
+ :undoc-members:
+ :show-inheritance:
\ No newline at end of file
diff --git a/template/docs/readme.rst b/template/docs/readme.rst
new file mode 100644
index 0000000..e2618b8
--- /dev/null
+++ b/template/docs/readme.rst
@@ -0,0 +1 @@
+.. mdinclude:: ../README.md
\ No newline at end of file
diff --git a/template/docs/{{ project_slug }}.rst.jinja b/template/docs/{{ project_slug }}.rst.jinja
new file mode 100644
index 0000000..d7d232c
--- /dev/null
+++ b/template/docs/{{ project_slug }}.rst.jinja
@@ -0,0 +1,71 @@
+{{ project_slug }}
+{% for _ in project_slug %}={% endfor %}
+
+.. toctree::
+ :maxdepth: 3
+ :hidden:
+
+ readme
+ api_reference
+ contributing
+ history
+
+
+{{ project_short_description }}
+
+{{ project_long_description }}
+
+.. grid:: 1 2 2 2
+ :gutter: 4
+
+ .. grid-item-card::
+ :link: readme.html
+ :text-align: center
+ :padding: 0 0 3 3
+
+ **Getting Started**
+ ^^^^
+
+ .. raw:: html
+
+
+
+
+ .. grid-item-card::
+ :link: api_reference
+ :link-type: ref
+ :text-align: center
+ :padding: 0 0 3 3
+
+ **API Reference**
+ ^^^^
+
+ .. raw:: html
+
+
+
+
+ .. grid-item-card::
+ :link: contributing.html
+ :text-align: center
+ :padding: 0 0 3 3
+
+ **Contributing**
+ ^^^^
+
+ .. raw:: html
+
+
+
+ .. grid-item-card::
+ :link: history.html
+ :text-align: center
+ :padding: 0 0 3 3
+
+ **History**
+ ^^^^
+
+ .. raw:: html
+
+
+
\ No newline at end of file
diff --git a/tests/test_copier.py b/tests/test_copier.py
index 9916393..071ad8c 100644
--- a/tests/test_copier.py
+++ b/tests/test_copier.py
@@ -13,6 +13,16 @@ def test_project_folder(default_project):
"pyproject.toml",
"my_project/__init__.py",
"my_project/my_project.py",
+ "docs/modules/my_project.rst",
+ "docs/my_project.rst",
+ "docs/api_reference.rst",
+ "docs/conf.py",
+ "docs/contributing.rst",
+ "docs/history.rst",
+ "docs/index.rst",
+ "docs/make.bat",
+ "docs/Makefile",
+ "docs/readme.rst",
])
def test_generated_file_exists(default_project, file_name):
assert default_project.project_dir.joinpath(file_name).exists()
@@ -110,3 +120,30 @@ def test_content_project_slug_init(default_project, desired):
content = default_project.project_dir.joinpath('my_project').joinpath(
"__init__.py").read_text()
assert desired in content, f"{desired!r} is not in content"
+
+
+@pytest.mark.parametrize("desired", [
+ "project = 'my_project'",
+ 'copyright = "2025, The pyfar developers"',
+ 'author = "The pyfar developers"',
+ "'numpy': ('https://numpy.org/doc/stable/', None)",
+ '\n "index": "my_project.html"',
+
+])
+def test_content_docs_conf(default_project, desired):
+ content = default_project.project_dir.joinpath('docs/conf.py').read_text()
+ assert desired in content, f"{desired!r} is not in content"
+
+
+@pytest.mark.parametrize("file_name", [
+ 'docs/modules/my_project.rst',
+ 'docs/my_project.rst',
+ 'docs/api_reference.rst',
+ 'docs/index.rst',
+ 'docs/make.bat',
+ 'docs/Makefile',
+])
+def test_content_docs_multiple_files(default_project, file_name):
+ content = default_project.project_dir.joinpath(file_name).read_text()
+ desired = "my_project"
+ assert desired in content, f"{desired!r} is not in content"