Repository: plone/plone.restapi (language: python)

Issue:
Browser tiltle of documentation still says version 1.0a1
https://plonerestapi.readthedocs.io/en/latest/searching.html

https://github.com/plone/plone.restapi/blob/03148b67af8026827b69a812796b50ae273c5857/docs/source/conf.py#L74


Discussion / hints:

Fix patch:
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 0bf1b9ba85..043663c1c4 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -18,7 +18,7 @@ build:
     # If there are no changes (git diff exits with 0) we force the command to return with 183.
     # This is a special exit code on Read the Docs that will cancel the build immediately.
     - |
-      if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ .readthedocs.yaml requirements-docs.txt requirements.txt;
+      if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && git diff --quiet origin/main -- docs/ src/plone/restapi/tests/http-examples/ .readthedocs.yaml requirements-docs.txt requirements.txt;
       then
         exit 183;
       fi
diff --git a/Makefile b/Makefile
index 71c500930e..2e931a857b 100644
--- a/Makefile
+++ b/Makefile
@@ -95,10 +95,13 @@ black:  ## Black
 zpretty:  ## zpretty
 	if [ -f "bin/zpretty" ]; then zpretty -i ./**/*.zcml; fi
 
+.PHONY: python-clean
+python-clean:  ## Clean Python virtual environment
+	rm -rf bin include lib
+
 .PHONY: docs-clean
-docs-clean:  ## Clean current and legacy docs build directories, and Python virtual environment
+docs-clean:  ## Clean current and legacy docs build directories
 	cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/
-	rm -rf bin include lib
 	rm -rf docs/build
 
 .PHONY: docs-html
diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css
deleted file mode 100644
index 09d09e359b..0000000000
--- a/docs/source/_static/custom.css
+++ /dev/null
@@ -1,353 +0,0 @@
-:root {
-  /* Add Font Awesome 5 icon and color for `todo` */
-  --pst-icon-clipboard-list: '\f46d';
-  --pst-icon-admonition-todo: var(--pst-icon-clipboard-list);
-  --pst-color-admonition-todo:  161 , 46, 233;
-  --target-color: #b9ee9e;
-  --codeblock-color: #aad993;
-}
-
-.visuallyhidden {
-  display: none;
-}
-pre {
-  border-radius: 0;
-  background-color: white;
-  box-shadow: none;
-}
-a,
-a:visited,
-main.bd-content #main-content a,
-main.bd-content #main-content a:visited {
-  color: #2980b9;
-}
-a:hover,
-main.bd-content #main-content a:hover {
-  color: #1a567e;
-  text-decoration: none;
-}
-ul {
-  list-style-type: square;
-}
-ul li > p {
-  margin-bottom: 0.3rem;
-}
-ol li > p {
-  margin-bottom: 0.3rem;
-}
-img{
-  margin: 1rem 0;
-}
-figure img,
-.figure img {
-  box-shadow: 0 6px 24px 0 rgba(153,153,153,0.3);
-}
-.sidebar img.logo {
-  box-shadow: none;
-  width: 200px;
-  margin-bottom: 1rem;
-}
-span.linenos {
-  padding-right: 1em;
-}
-p.ploneorglink img {
-  vertical-align: bottom;
-}
-dt:target,
-span.highlighted,
-ul.search li span.highlighted {
-  background-color: var(--target-color);
-}
-
-.bd-sidebar .nav ul {
-  padding: 0 0 0 1rem;
-}
-.bd-sidebar .nav .toctree-checkbox ~ label i {
-  transform: rotate(90deg);
-}
-.bd-sidebar .nav .toctree-checkbox:checked ~ label i {
-  transform: rotate(0deg);
-}
-
-.toctree-wrapper .caption {
-  font-weight: bold;
-  font-size: 1.2em;
-  margin-top: 3rem;
-}
-.toctree-wrapper ul {
-  list-style: none;
-}
-
-section:not(#glossary) h1 ~ dl {
-  display: grid;
-  grid-template-columns: max-content auto;
-}
-section:not(#glossary) h1 ~ dl dd {
-  margin-bottom: unset !important;
-}
-
-div.section {
-  margin-bottom: 5rem;
-}
-
-/* admonitions */
-.admonition {
-  border-radius: 0;
-  border: none;
-  border-left: .2rem solid;
-  border-left-color: rgba(var(--pst-color-admonition-default),1);
-}
-.admonition .admonition-title {
-  margin-bottom: 1.5rem !important;
-}
-.admonition.toggle .admonition-title {
-  cursor: pointer;
-  display: flex;
-}
-.admonition.toggle .admonition-title::after {
-  content: "\f105";
-  font-weight: 900;
-  font-family: "Font Awesome 5 Free";
-  margin-left: auto;
-}
-.admonition.toggle .admonition-title.open::after {
-  content: "\f107";
-}
-/* admonition `todo` */
-.admonition.admonition-todo,
-div.admonition.admonition-todo {
-  border-color: rgba(var(--pst-color-admonition-todo),1);
-}
-.admonition.admonition-todo > .admonition-title,
-div.admonition.admonition-todo > .admonition-title {
-  background-color: rgba(var(--pst-color-admonition-todo),.1);
-}
-.admonition.admonition-todo > .admonition-title::before,
-div.admonition.admonition-todo > .admonition-title::before {
-  color: rgba(var(--pst-color-admonition-todo),1);
-  content: var(--pst-icon-admonition-todo);
-}
-.admonition-github-only.admonition {
-  display: none;
-}
-
-
-.topic {
-  padding: 1.5em 1em .5em 1em;
-}
-.topic-title {
-  font-weight: bold;
-}
-
-
-/* Bootstrap */
-.btn-primary {
-  color: #fff;
-  background-color: #2980b9;
-  border-color: #2980b9;
-}
-.btn-primary {
-  background-color: #1f86ca;
-  border-color: #2980b9;
-}
-
-/* Search */
-
-/* Show search form. It is hidden by default. */
-#search-documentation,
-#search-documentation~form,
-#search-documentation~p {
- display:block;
-}
-ul.search {
-  margin-left: 0;
-}
-p.search-summary {
-  margin: 1em 0 2rem 0;
-}
-#search-results ul {
-  list-style-type: none;
-  padding-left: 0;
-}
-#search-results ul li,
-ul.search li {
-  margin-bottom: 2rem;
-  padding: 0;
-  background-image: none;
-  border-bottom: none;
-}
-#search-results ul li h3 {
-  margin: 0.4rem 0 .5rem;
-  font-size: 1.5rem;
-}
-#search-results ul li .breadcrumbs {
-  display: flex;
-  flex-direction: row;
-  flex-wrap: wrap;
-}
-#search-results ul li .breadcrumbs a {
-  font-weight: normal;
-}
-#search-results ul li .breadcrumbs .lastbreadcrumb {
-  white-space: nowrap;
-  display: inline-block;
-  max-width: 12rem;
-  overflow: hidden;              /* "overflow"-Wert darf nicht "visible" sein */
-
-  text-overflow: ellipsis;
-}
-ul.search li p.context {
-  margin-left: 0;
-}
-.pathseparator {
-  padding: 0 0.7rem;
-}
-
-
-/* submenu */
-.bd-toc {
-  box-shadow: 0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);
-}
-
-/* extra sidebar */
-div.sidebar:not(.margin){
-  width: 40%;
-  float: right;
-  clear: right;
-  margin: .3rem 0 .3rem 0.5em;
-  padding: 2rem 0 1.5rem 1rem !important;
-  background-color: rgba(var(--pst-color-admonition-note),.1);
-  border: none;
-  border-left: 8px rgba(var(--pst-color-admonition-default),1) solid;
-  border-radius: .2rem;
-  box-shadow: 0 .2rem .5rem rgba(0,0,0,.05),0 0 .0625rem rgba(0,0,0,.1);
-}
-
-div.sidebar:not(.margin) .figure {
-  margin-top: 0;
-  padding-top: 0;
-  margin-left: 0;
-  padding-left: 0;
-}
-div.sidebar:not(.margin) img.logo {
-  margin-top: 0;
-  margin-bottom: .3rem;
-}
-div.sidebar:not(.margin) p {
-  margin-bottom: 0;
-}
-div.sidebar:not(.margin) p.sidebar-title {
-  display: none;
-}
-div.sidebar:not(.margin) div.topic {
-  padding: .5em 0;
-  background-color: transparent;
-  border: none;
-}
-div.sidebar:not(.margin) pre {
-  margin: .5em 0 1.5em 0;
-}
-div.sidebar:not(.margin) div[class*="highlight-"] {
-  margin-right: .5em;
-}
-div.sidebar:not(.margin) .admonition {
-  margin-right: .5em;
-  background-color: #ffffff;
-}
-@media (min-width:768px) {
-  div.sidebar:not(.margin) {
-    width: 50%;
-    margin-left: 1.5em;
-    margin-right: -28%;
-  }
-}
-
-
-main.bd-content #main-content dl.simple dt {
-  margin-top: .8em;
-}
-main.bd-content #main-content dl.simple dt:nth-of-type(1) {
-  margin-top: 0;
-}
-main.bd-content #main-content dl.simple dd {
-  margin-top: .8em;
-}
-main.bd-content #main-content dl.simple dt + dd {
-  margin-top: 0;
-}
-
-.prev-next-bottom {
-  margin: 20px 0 30px 0;
-}
-.prev-next-bottom a.left-prev, .prev-next-bottom a.right-next {
-  padding: 5px 10px;
-  border: 1px solid rgba(0,0,0,.2);
-  max-width: 45%;
-  overflow-x: hidden;
-  color: rgba(0,0,0,.65);
-  border-radius: 10px;
-}
-
-/* Local navigation */
-li.nav-item.toc-entry {
-  line-height: 1.25em;
-  margin-bottom: 0.25em;
-}
-
-span.guilabel, span.menuselection {
-  border: none;
-  background: #e7f2fa;
-  border-radius: 4px;
-  padding: 4px 5px;
-  font-size: 90%;
-  font-weight: bold;
-  font-style: italic;
-  white-space: nowrap;
-}
-
-
-/*
- * extensions
- */
-
-/* definitions */
-dl.py.function {
-  margin-bottom: 5rem;
-}
-dl.py.function > dt {
-  background-color: var(--codeblock-color);
-  padding: 4px 5px;
-}
-dl.py.function > dt:target {
-  background-color: var(--target-color);
-}
-dl.field-list > dt {
-  padding-left: 0;
-}
-
-/* code blocks */
-div.viewcode-block:target {
-  padding: 10px 10px;
-  background-color: var(--codeblock-color);
-  border-top: 1px solid var(--codeblock-color);
-  border-bottom: 1px solid var(--codeblock-color);
-}
-
-/*  Hint for providing the Unicode Value of an fa-icon in CSS as ASCII
-    replace the "&#x" part from the unicode HTML5 literal 
-    displayed on the font-awesome website cheatsheet e.g. 
-    http://fontawesome.io/cheatsheet/
-   
-        fa-wrench [&#xf0ad;]
-
-    by a backslash like:
-
-        .fa-wrench:before {
-            content: "\f0ad";
-        }
-*/
-
-.icon-wrench:before,
-.fa-wrench:before {
-    content: "\f0ad";
-}
diff --git a/docs/source/_static/print.css b/docs/source/_static/print.css
deleted file mode 100644
index 8dbc2d5794..0000000000
--- a/docs/source/_static/print.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.tooltip {
-  display: none;
-}
diff --git a/docs/source/_templates/page.html b/docs/source/_templates/page.html
deleted file mode 100644
index 35e79d84c1..0000000000
--- a/docs/source/_templates/page.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "!page.html" %}
-
-{% set css_files = css_files + ["_static/custom.css"] %}
-
-{% block footer %}
- <script type="text/javascript">
-    $(document).ready(function() {
-        $(".toggle > *").hide();
-        $(".toggle .admonition-title").show();
-        $(".toggle .admonition-title").click(function() {
-            $(this).parent().children().not(".admonition-title").toggle(400);
-            $(this).parent().children(".admonition-title").toggleClass("open");
-        })
-    });
-</script>
-{% endblock %}
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
index c1cb7ad6f7..5bc2f084a2 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -26,6 +26,8 @@
 
 # General information about the project.
 project = "plone.restapi"
+author = "Plone Community"
+trademark_name = "Plone"
 thisyear = datetime.datetime.now().year
 copyright = "2014-%s, Plone Foundation" % thisyear
 
@@ -159,50 +161,85 @@ def patch_pygments_to_highlight_jsonschema():
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = "sphinx_book_theme"
+html_theme = "plone_sphinx_theme"
 
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
 html_logo = "_static/logo.svg"
-html_favicon = "_static/favicon.ico"
 
-html_css_files = ["custom.css", ("print.css", {"media": "print"})]
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = "_static/favicon.ico"
 
 # See http://sphinx-doc.org/ext/todo.html#confval-todo_include_todos
 todo_include_todos = True
 
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+html_title = "%(project)s v%(release)s" % {"project": project, "release": release}
+
+# 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 = {
+    "extra_footer": """<p>The text and illustrations in this website are licensed by the Plone Foundation under a Creative Commons Attribution 4.0 International license. Plone and the Plone® logo are registered trademarks of the Plone Foundation, registered in the United States and other countries. For guidelines on the permitted uses of the Plone trademarks, see <a href="https://plone.org/foundation/logo">https://plone.org/foundation/logo</a>. All other trademarks are owned by their respective owners.</p>
+    <p>Pull request previews by <a href="https://readthedocs.org/">Read the Docs</a>.</p>""",
+    "footer_end": ["version.html"],
+    "icon_links": [
+        {
+            "name": "GitHub",
+            "url": "https://github.com/plone/plone.restapi",
+            "icon": "fa-brands fa-square-github",
+            "type": "fontawesome",
+            "attributes": {
+                "target": "_blank",
+                "rel": "noopener me",
+                "class": "nav-link custom-fancy-css"
+            }
+        },
+        {
+            "name": "Mastodon",
+            "url": "https://plone.social/@plone",
+            "icon": "fa-brands fa-mastodon",
+            "type": "fontawesome",
+            "attributes": {
+                "target": "_blank",
+                "rel": "noopener me",
+                "class": "nav-link custom-fancy-css"
+            }
+        },
+        {
+            "name": "Twitter",
+            "url": "https://twitter.com/plone",
+            "icon": "fa-brands fa-square-twitter",
+            "type": "fontawesome",
+            "attributes": {
+                "target": "_blank",
+                "rel": "noopener me",
+                "class": "nav-link custom-fancy-css"
+            }
+        },
+    ],
+    "logo": {
+        "text": html_title,
+    },
+    "navigation_with_keys": True,
     "path_to_docs": "docs",
-    "repository_url": "https://github.com/plone/plone.restapi",
     "repository_branch": "master",
-    "use_repository_button": True,
-    "use_issues_button": True,
+    "repository_url": "https://github.com/plone/plone.restapi",
+    "search_bar_text": "Search",  # TODO: Confirm usage of search_bar_text
     "use_edit_page_button": True,
-    "extra_footer": """<p>The text and illustrations in this website are licensed by the Plone Foundation under a Creative Commons Attribution 4.0 International license. Plone and the Plone® logo are registered trademarks of the Plone Foundation, registered in the United States and other countries. For guidelines on the permitted uses of the Plone trademarks, see <a href="https://plone.org/foundation/logo">https://plone.org/foundation/logo</a>. All other trademarks are owned by their respective owners.</p>""",
+    "use_issues_button": True,
+    "use_repository_button": True,
 }
 
-# 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 themes here, relative to this directory.
 # html_theme_path = []
 
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-html_title = "%(project)s v%(release)s" % {"project": project, "release": release}
-
 # A shorter title for the navigation bar.  Default is the same as html_title.
 # html_short_title = None
 
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
 # 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".
@@ -274,12 +311,14 @@ def patch_pygments_to_highlight_jsonschema():
 # For more information see:
 # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html
 myst_enable_extensions = [
-    "deflist",  # You will be able to utilise definition lists
+    "deflist",  # Support definition lists.
     # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#definition-lists
-    "linkify",  # Identify “bare” web URLs and add hyperlinks.
+    "linkify",  # Identify "bare" web URLs and add hyperlinks.
     "colon_fence",  # You can also use ::: delimiters to denote code fences,\
     #  instead of ```.
-    "substitution",  # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#substitutions-with-jinja2
+    "substitution",  # plone.restapi \
+    # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#substitutions-with-jinja2
+    "html_image",  # For inline images. See https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#html-images
 ]
 
 myst_substitutions = {
diff --git a/news/1815.documentation b/news/1815.documentation
new file mode 100644
index 0000000000..dd9891dfe5
--- /dev/null
+++ b/news/1815.documentation
@@ -0,0 +1,1 @@
+Use Plone Sphinx Theme for documentation. Build docs when there are changes to http-examples. @stevepiercy
diff --git a/requirements-docs.txt b/requirements-docs.txt
index a522f65309..4b3918f397 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,20 +1,10 @@
-docutils<0.17,>=0.15  # sphinx-book-theme 0.2.0 has requirement docutils<0.17,>=0.15
-Sphinx<5,>=3  # sphinx-book-theme 0.3.3 has requirement sphinx<5,>=3
-sphinxcontrib-applehelp==1.0.4  # newer versions require sphinx 5
-sphinxcontrib-devhelp==1.0.2   # newer versions require sphinx 5
-sphinxcontrib-htmlhelp==2.0.1  # newer versions require sphinx 5
-sphinxcontrib-qthelp==1.0.3  # newer versions require sphinx 5
-sphinxcontrib-serializinghtml==1.1.5  # newer versions require sphinx 5
-jsx-lexer
-lesscpy
 linkify-it-py
 myst-parser
+plone-sphinx-theme
+setuptools  # required by sphinxcontrib.httpexample, remove when it migrates to importlib
 sphinx-autobuild
-sphinx-book-theme
 sphinx-copybutton
-sphinx-sitemap
-sphinx-togglebutton
 sphinxcontrib.httpdomain
 sphinxcontrib.httpexample
-sphinxcontrib-spelling
 sphinxext-opengraph
+vale==2.30.0


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index b354a9e4d5..64f7dc2ee6 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -50,7 +50,7 @@ jobs:
       - run: pip install virtualenv
       - run: pip install wheel
       - name: pip install
-        run: pip install -r requirements-${{ matrix.plone-version }}.txt -r requirements-docs.txt
+        run: pip install -r requirements-${{ matrix.plone-version }}.txt
 
       # buildout
       - name: buildout
@@ -60,7 +60,7 @@ jobs:
 
       # build sphinx
       - name: sphinx
-        run: if [ "${{ matrix.plone-version }}" == "6.0" ] && [ ${{ matrix.python-version }} == '3.12' ]; then make docs-html; fi
+        run: if [ "${{ matrix.plone-version }}" == "6.0" ] && [ ${{ matrix.python-version }} == '3.12' ]; then pip install -r requirements-docs.txt && make docs-html; fi
 
       # test
       - name: test