diff --git a/.gitignore b/.gitignore index c732858ee..94c3fee6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +*.csv +!redirects.csv +.env + _build/ env/ __pycache__ @@ -40,3 +44,6 @@ logo.h # Output of list-unused-images.sh tool tmp-unused-images tmp-unused-images-history + +# User created Python virtual environement as described in the docs +godot-docs-venv/ diff --git a/Makefile b/Makefile index f1fa052cf..200ce1c84 100644 --- a/Makefile +++ b/Makefile @@ -1,199 +1,37 @@ # Makefile for Sphinx documentation -# -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build -LATEXDEPS = latex dvipng +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SPHINXSOURCEDIR ?= . +SPHINXBUILDDIR ?= _build +SPHINXPAPER ?= +FILELIST ?= # User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD make variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +ifneq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 0) +define ERROR_MESSAGE +The '$(SPHINXBUILD)' command was not found! +Make sure you have Sphinx installed, then set the SPHINXBUILD make variable to the full path of the '$(SPHINXBUILD)' executable. +Alternatively you can add the executable's directory to your PATH. +If you don't have Sphinx installed, grab it from http://sphinx-doc.org/ +endef +$(error ${ERROR_MESSAGE}) endif -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) -t i18n . +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +COMMONSPHINXOPTS = $(PAPEROPT_$(SPHINXPAPER)) $(SPHINXOPTS) '$(SPHINXSOURCEDIR)' +DEFAULTSPHINXOPTS = -d $(SPHINXBUILDDIR)/doctrees $(COMMONSPHINXOPTS) -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext +.PHONY: help clean help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - @echo " dummy to run only the parse steps without generating output" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GodotEngine.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GodotEngine.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/GodotEngine" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GodotEngine" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + @$(SPHINXBUILD) -M help $(DEFAULTSPHINXOPTS) $(O) "$(SPHINXBUILDDIR)" +# This is used by https://github.com/godotengine/godot-docs-l10n +# See https://github.com/godotengine/godot-docs-l10n/blob/f157c0cacc8a6e542e06e96b983b27de91637f8b/update.sh#L92 gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) ../sphinx/templates - @echo - @echo "Build finished. The message catalogs are in ../sphinx/templates." + $(SPHINXBUILD) -b gettext -t i18n $(COMMONSPHINXOPTS) ../sphinx/templates $(FILELIST) -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." - -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. No output." +%: + $(SPHINXBUILD) -M $@ $(DEFAULTSPHINXOPTS) $(O) "$(SPHINXBUILDDIR)"/$@ $(FILELIST) diff --git a/_static/css/custom.css b/_static/css/custom.css index 3dd77188e..3379f5f50 100644 --- a/_static/css/custom.css +++ b/_static/css/custom.css @@ -5,21 +5,47 @@ * based on browser preferences. */ + @font-face { + font-family: "JetBrains Mono"; + src: url('fonts/JetBrainsMono-Regular.woff2'); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: "JetBrains Mono"; + src: url('fonts/JetBrainsMono-Medium.woff2'); + font-weight: 600; + font-style: normal; +} +@font-face { + font-family: "JetBrains Mono"; + src: url('fonts/JetBrainsMono-Bold.woff2'); + font-weight: 700; + font-style: normal; +} + /* Default (light) theme colors */ :root { --body-color: #404040; --content-wrap-background-color: #efefef; --content-background-color: #fcfcfc; --logo-opacity: 1.0; + --navbar-background-color: #333f67; --navbar-background-color-hover: #29355c; --navbar-background-color-active: #212d51; --navbar-current-background-color: #212d51; --navbar-current-background-color-hover: #182343; --navbar-current-background-color-active: #131e3b; + --navbar-category-active-color: rgba(255 115 129 / 10%); + --navbar-current-color: #f1f9ff; --navbar-level-1-color: #c3e3ff; --navbar-level-2-color: #b8d6f0; --navbar-level-3-color: #a3c4e1; + --navbar-expand-base-color: #81a3c2; + --navbar-expand-hover-color: #c3e3ff; + --navbar-expand-active-color: #f1f9ff; + --navbar-dimmed-color: #a3c4e1; --navbar-heading-color: #ff7381; --navbar-scrollbar-color: #d45a66; --navbar-scrollbar-hover-color: #b14550; @@ -30,16 +56,26 @@ --link-color-hover: #3091d1; --link-color-active: #105078; --link-color-visited: #9b59b6; + --class-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjIiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNS4wMjkgMWMtLjk5OS0uMDExLTIuMDA5LjMxMi0zLjAyOSAxdjdjMi4wMTctMS4zNTMgNC4wMTctMS4zMTQgNiAwIDEuOTgzLTEuMzE0IDMuOTgzLTEuMzUzIDYgMHYtN2MtMS4wMi0uNjg4LTIuMDMtMS4wMTEtMy4wMjktMS0uNjYyLjAwNy0xLjMxOC4xNzMtMS45NzEuNDYzdjQuNTM3aC0xdi00Yy0uOTgyLS42NDUtMS45NzEtLjk4OS0yLjk3MS0xem0tNS4wMjkgOXY2aDJjMS42NDYgMCAzLTEuMzU0IDMtM3MtMS4zNTQtMy0zLTN6bTUgM2MwIDEuNjQ2IDEuMzU0IDMgMyAzczMtMS4zNTQgMy0zLTEuMzU0LTMtMy0zLTMgMS4zNTQtMyAzem02IDBjMCAxLjY0NiAxLjM1NCAzIDMgM2gxdi0yaC0xYy0uNTQ5IDAtMS0uNDUxLTEtMXMuNDUxLTEgMS0xaDF2LTJoLTFjLTEuNjQ2IDAtMyAxLjM1NC0zIDN6bS05LTFjLjU0OSAwIDEgLjQ1MSAxIDFzLS40NTEgMS0xIDF6bTYgMGMuNTQ5IDAgMSAuNDUxIDEgMXMtLjQ1MSAxLTEgMS0xLS40NTEtMS0xIC40NTEtMSAxLTF6IiBmaWxsPSIjNDE0MTQxIiBmaWxsLW9wYWNpdHk9Ii41OSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+Cg=="); --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjk4MGI5Ij48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); --hr-color: #e1e4e5; --table-row-odd-background-color: #f3f6f6; - --code-background-color: #fff; + --code-background-color: #e9eae5; --code-border-color: #e1e4e5; - --code-literal-color: #d04c60; + --code-literal-color: #c03e41; --input-background-color: #fcfcfc; --input-focus-border-color: #5f8cff; + --tabs-background-color: #e1e4e5; + --tabs-selected-color: #a2a9ae; + --code-tabs-background-color: #e3ecd1; + --code-tabs-selected-color: #8a9378; + + --classref-primary-color: #252525; + --classref-secondary-color: #616770; + --classref-setget-color: #56585b; + --search-input-background-color: #e6eef3; /* derived from --input-background-color */ --search-match-color: #2c6b96; /* derived from --link-color */ --search-match-background-color: #e3f2fd; /* derived from --link-color */ @@ -48,6 +84,11 @@ --search-credits-color: #b3b3b3; /* derived from --footer-color */ --search-credits-link-color: #4392c5; /* derived from --link-color */ + --search-odd-color: rgb(133 160 253 / 24%); + --search-even-color: rgb(202 209 239 / 30%); + --search-highlighted-color: rgb(255 205 0 / 25%); + --search-context-color: #6c6e72; + --highlight-background-color: #f5ffe1; --highlight-background-emph-color: #dbe6c3; --highlight-default-color: #404040; @@ -62,6 +103,9 @@ --highlight-operator-color: #666666; --highlight-string-color: #4070a0; + --contribute-background-color: #d7dee8; + --contribute-text-color: #646e72; + --admonition-note-background-color: #e7f2fa; --admonition-note-color: #404040; --admonition-note-title-background-color: #6ab0de; @@ -84,9 +128,15 @@ --kbd-shadow-color: #b0b7bf; --kbd-text-color: #444d56; + --code-example-good-color: #3fb950; + --code-example-bad-color: #f85149; + --btn-neutral-background-color: #f3f6f6; --btn-neutral-hover-background-color: #e5ebeb; --footer-color: #808080; + + --system-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --monospace-font-family: "JetBrains Mono", SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, Courier, monospace; } /* Dark theme colors */ @@ -97,15 +147,22 @@ --content-background-color: #2e3236; /* Decrease the logo opacity when using the dark theme to be less distracting */ --logo-opacity: 0.85; + --navbar-background-color: #25282b; --navbar-background-color-hover: #333639; --navbar-background-color-active: #111417; --navbar-current-background-color: #333639; --navbar-current-background-color-hover: #44474a; --navbar-current-background-color-active: #222528; + --navbar-category-active-color: rgba(238 115 129 / 10%); + --navbar-current-color: #fefefe; --navbar-level-1-color: #ddd; --navbar-level-2-color: #ccc; --navbar-level-3-color: #bbb; + --navbar-expand-base-color: #80848e; + --navbar-expand-hover-color: #ccc; + --navbar-expand-active-color: #ddd; + --navbar-dimmed-color: #bbb; --navbar-heading-color: #ee7381; --navbar-scrollbar-color: #be5460; --navbar-scrollbar-hover-color: #963e48; @@ -116,16 +173,26 @@ --link-color-hover: #9df; --link-color-active: #6ad; --link-color-visited: #cb99f6; + --class-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjIiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNS4wMjkgMWMtLjk5OS0uMDExLTIuMDA5LjMxMi0zLjAyOSAxdjdjMi4wMTctMS4zNTMgNC4wMTctMS4zMTQgNiAwIDEuOTgzLTEuMzE0IDMuOTgzLTEuMzUzIDYgMHYtN2MtMS4wMi0uNjg4LTIuMDMtMS4wMTEtMy4wMjktMS0uNjYyLjAwNy0xLjMxOC4xNzMtMS45NzEuNDYzdjQuNTM3aC0xdi00Yy0uOTgyLS42NDUtMS45NzEtLjk4OS0yLjk3MS0xem0tNS4wMjkgOXY2aDJjMS42NDYgMCAzLTEuMzU0IDMtM3MtMS4zNTQtMy0zLTN6bTUgM2MwIDEuNjQ2IDEuMzU0IDMgMyAzczMtMS4zNTQgMy0zLTEuMzU0LTMtMy0zLTMgMS4zNTQtMyAzem02IDBjMCAxLjY0NiAxLjM1NCAzIDMgM2gxdi0yaC0xYy0uNTQ5IDAtMS0uNDUxLTEtMXMuNDUxLTEgMS0xaDF2LTJoLTFjLTEuNjQ2IDAtMyAxLjM1NC0zIDN6bS05LTFjLjU0OSAwIDEgLjQ1MSAxIDFzLS40NTEgMS0xIDF6bTYgMGMuNTQ5IDAgMSAuNDUxIDEgMXMtLjQ1MSAxLTEgMS0xLS40NTEtMS0xIC40NTEtMSAxLTF6IiBmaWxsPSIjYmZiZmJmIiBmaWxsLW9wYWNpdHk9Ii41OSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+Cg=="); --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOGNmIj48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K"); --hr-color: #555; --table-row-odd-background-color: #3b3e41; - --code-background-color: #434649; + --code-background-color: #22252d; --code-border-color: #505356; - --code-literal-color: #faa; + --code-literal-color: #d68f8f; --input-background-color: #333537; --input-focus-border-color: #5f8cff; + --tabs-background-color: #434649; + --tabs-selected-color: #a2a9ae; + --code-tabs-background-color: #353c4c; + --code-tabs-selected-color: #5a657e; + + --classref-primary-color: #e8e8e8; + --classref-secondary-color: #929598; + --classref-setget-color: #9e9fa0; + --search-input-background-color: #43464a; /* derived from --input-background-color */ --search-match-color: #52b4ff; /* derived from --link-color */ --search-match-background-color: #414c56; /* derived from --link-color */ @@ -134,6 +201,11 @@ --search-credits-color: #6b6b6b; /* derived from --footer-color */ --search-credits-link-color: #628fb1; /* derived from --link-color */ + --search-odd-color: #202326; + --search-even-color: #25282b; + --search-highlighted-color: rgb(255 205 0 / 16%); + --search-context-color: #aaa; + /* Colors taken from the Godot script editor with the Adaptive theme */ --highlight-background-color: #202531; --highlight-background-emph-color: #2d3444; @@ -142,13 +214,16 @@ --highlight-keyword-color: #ff7085; --highlight-keyword2-color: #42ffc2; --highlight-number-color: #a1ffe0; - --highlight-decorator-color: #abc8ff; + --highlight-decorator-color: #ffb373; --highlight-type-color: #8effda; --highlight-type2-color: #c6ffed; --highlight-function-color: #57b3ff; --highlight-operator-color: #abc8ff; --highlight-string-color: #ffeca1; + --contribute-background-color: #25282d; + --contribute-text-color: #7f939b; + --admonition-note-background-color: #303d4f; --admonition-note-color: #bfeeff; --admonition-note-title-background-color: #305070; @@ -171,6 +246,9 @@ --kbd-shadow-color: #1e2023; --kbd-text-color: #e2f2ff; + --code-example-good-color: #3fb950; + --code-example-bad-color: #f85149; + --btn-neutral-background-color: #404040; --btn-neutral-hover-background-color: #505050; --footer-color: #aaa; @@ -194,7 +272,9 @@ legend, .rst-content .toctree-wrapper p.caption, .rst-versions { /* Use a system font stack for better performance (no Web fonts required) */ - font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: var(--system-font-family); + /* Some fonts that we use (namely JetBrains Mono) can come with ligatures. It's better to opt-in if needed. */ + font-variant-ligatures: none; } h1, @@ -236,14 +316,21 @@ article ol, .wy-plain-list-disc, .wy-plain-list-decimal, .rst-content ol.arabic, -.rst-content .section ul, -.rst-content .toctree-wrapper ul, -.rst-content .section ol { +.rst-content .toctree-wrapper ul { /* Increase the line height slightly to account for the different font */ line-height: 25px; } -.rst-content section ul li { +/* Depending on the environment, it can be a section tag or a div with the section class. */ +.rst-content section ul, +.rst-content section ol, +.rst-content .section ul, +.rst-content .section ol { + /* Increase the line height slightly to account for the different font */ + line-height: 25px; +} +.rst-content section ul li, +.rst-content .section ul li { /* Increase spacing between list items. */ margin-top: 8px; margin-bottom: 8px; @@ -258,19 +345,6 @@ a { color: var(--link-color); } -.sphinx-tabs-tab { - color: var(--link-color); -} - -.sphinx-tabs-tab[aria-selected="true"] { - background-color: var(--code-background-color); - border-bottom: 1px solid var(--code-background-color); -} - -.sphinx-tabs-panel { - background-color: var(--code-background-color); -} - a:hover { color: var(--link-color-hover); text-decoration: underline; @@ -297,12 +371,85 @@ a.btn:hover { padding-right: 13px; } +/* Distinguish class reference page links from "user manual" page links with a class reference badge. */ + +/* Remove text wrapping so that the badge is always on the same line as the anchor's text. */ +.rst-content a[href*="classes/"] { + white-space: nowrap; +} +/* Add an icon as a badge, after the anchor's text. */ +.rst-content a[href*="classes/"]::after { + content: ""; + background-image: var(--class-reference-icon); + display: inline-block; + height: 16px; + width: 16px; + padding: 0.125rem 0.375rem; + margin-left: 0.25rem; +} + +/* Prevent the class reference badge from appearing twice in the instant search results (not testable locally). */ +.wy-body-for-nav .search__result__single a[href*="classes/"]::after { + display: none; +} +.wy-body-for-nav .search__result__single a[href*="classes/"]:first-child::after { + display: inline-block; +} +/* Prevent the class reference badge from appearing several times per item in the dedicated search results page. */ +#search-results .context a[href*="classes/"]::after { + display: none; +} + +/* Stylize horizontal separator, mainly for the search results page. */ hr, #search-results .search li:first-child, #search-results .search li { border-color: var(--hr-color); } +/* Stylize the search results page. */ +#search-results .search-summary { + color: var(--footer-color); +} + +#search-results .context { + color: var(--search-context-color); + padding-left: 14px; + position: relative; +} + +#search-results .context:before { + content: "•"; + display: block; + position: absolute; + left: 0; + font-size: 120%; +} + +#search-results .search li { + background-color: var(--search-odd-color); + padding: 16px 14px; + border-radius: 6px; + border: none; + margin-bottom: 18px; +} + +#search-results .search li:first-child { + border: none; + padding: 16px 14px; + margin-top: 20px; +} + +#search-results .search li:nth-child(2n) { + background-color: var(--search-even-color); +} + +/* Add more visual separation for the title of a search result island. */ +#search-results .search li > a:first-child { + font-weight: 600; + font-size: 140%; +} + /* JavaScript documentation directives */ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list) > dt { @@ -328,7 +475,7 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).function > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).method > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple).attribute > dt { - font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, Courier, monospace; + font-family: var(--monospace-font-family); font-size: 90%; font-weight: normal; margin-bottom: 16px; @@ -379,11 +526,10 @@ html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not( color: var(--link-color-visited); } html.writer-html5 .rst-content dl.field-list > dd strong { - font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, Courier, monospace; + font-family: var(--monospace-font-family); } -footer, -#search-results .context { +footer { color: var(--footer-color); } @@ -494,6 +640,7 @@ footer, .wy-nav-content { background-color: var(--content-background-color); + max-width: 900px; } .wy-body-for-nav { @@ -503,20 +650,80 @@ footer, @media only screen and (min-width: 769px) { .wy-body-for-nav { /* Center the page on wide displays for better readability */ - max-width: 1100px; + max-width: 1200px; margin: 0 auto; } } +/* Customize the look of tabbed panels, including code tabs. */ + +.rst-content [role="tablist"] { + border-bottom: none; +} + +.rst-content .sphinx-tabs-tab { + border-top: 4px solid transparent; + color: var(--link-color); + padding: 0.5rem 1.25rem; +} + +.rst-content .sphinx-tabs-tab[aria-selected="true"] { + background-color: var(--tabs-background-color); + border: none; + border-radius: 0; + border-top: 4px solid var(--tabs-selected-color); +} +.rst-content .sphinx-tabs-tab.code-tab[aria-selected="true"] { + background-color: var(--code-tabs-background-color); + border-top: 4px solid var(--code-tabs-selected-color); +} + +.rst-content .sphinx-tabs-tab:focus { + z-index: inherit; +} + +.rst-content .sphinx-tabs-panel { + background-color: var(--tabs-background-color); + border: none; + border-radius: 0; +} +.rst-content .sphinx-tabs-panel.code-tab { + background-color: var(--code-tabs-background-color); +} + +.rst-content .sphinx-tabs-panel div[class^="highlight"] { + border: none; + box-shadow: none; + margin-bottom: 2px; +} + +.rst-content div[class^="highlight"] pre { + font-variant-ligatures: none; + padding: 18px 16px; +} + /* Table display tweaks */ .rst-content table.docutils, +.wy-table-bordered-all { + border: 4px solid var(--code-border-color); +} + .wy-table-bordered-all td, -.rst-content table.docutils td, .wy-table thead th, +.rst-content table.docutils td, .rst-content table.docutils thead th, .rst-content table.field-list thead th { - border-color: var(--code-border-color); + border-bottom: 2px solid var(--code-border-color); + border-left: 2px solid var(--code-border-color); + padding: 4px 16px; +} + +html.writer-html5 .rst-content table.docutils th { + border-bottom: 4px solid var(--code-border-color); + border-left: 2px solid var(--code-border-color); + padding: 8px 16px; + vertical-align: middle; } .wy-table-odd td, @@ -531,29 +738,65 @@ footer, .wy-table-responsive table th:not(:nth-child(1)) { white-space: normal; } +/* Allow to control wrapping behavior per table */ +.wy-table-responsive table.wrap-normal td, +.wy-table-responsive table.wrap-normal th { + white-space: normal; +} + +/* Make sure line blocks don't stretch tables */ +.wy-table-responsive table .line-block { + margin-bottom: 0; +} + /* Make sure not to wrap keyboard shortcuts */ .wy-table-responsive table td kbd { white-space: nowrap; } +/* Artificially increasing specificity to make it override theme.css. */ +html.writer-html5 .rst-content .wy-table-responsive > table td > p { + line-height: 1.425rem; +} +html.writer-html5 .rst-content .wy-table-responsive > table th > p { + line-height: 1.425rem; + font-size: .95rem; + font-weight: 600; +} + +html.writer-html5 .rst-content .wy-table-responsive > table td > p tt.literal, +html.writer-html5 .rst-content .wy-table-responsive > table td > p code.literal { + font-size: .85rem; + padding: 2px 5px; +} + /* Code display tweaks */ code, .rst-content tt, .rst-content code { font-size: 14px; + font-family: var(--monospace-font-family); background-color: var(--code-background-color); - border: 1px solid var(--code-border-color); + border: none; + border-radius: 4px; } .rst-content tt.literal, .rst-content code.literal { color: var(--code-literal-color); + font-weight: 600; + font-variant-ligatures: none; + padding: 3px 5px; } .rst-content div[class^="highlight"] { - border-color: var(--code-border-color); + border: 3px solid var(--code-tabs-background-color); +} + +.rst-content div[class^="highlight"] div[class^="highlight"] { + box-shadow: none; } .rst-content pre.literal-block, @@ -562,6 +805,7 @@ code, /* Increase the font size and line height in code blocks */ font-size: 14px; line-height: 1.5; + font-family: var(--monospace-font-family); } /* Code tab display tweaks */ @@ -679,18 +923,59 @@ code, color: var(--highlight-string-color); } -/* Admonition tweaks */ +/* Call to action for missing documentation */ +.rst-content .contribute { + background-color: var(--contribute-background-color); + color: var(--contribute-text-color); + padding: 12px; + margin-bottom: 12px; +} +.rst-content .contribute > p { + margin-bottom: 0; +} + +/* Admonition tweaks */ +.rst-content .admonition-grid { + display: grid; + grid-template-columns: 1fr; + gap: 20px; +} +.rst-content .admonition-grid-2x { + grid-template-columns: 4fr 5fr; +} +@media screen and (max-width: 1020px) { + .rst-content .admonition-grid { + gap: 12px; + } + .rst-content .admonition-grid-2x { + grid-template-columns: 1fr; + } +} + +.rst-content .admonition, .rst-content .admonition.note, .rst-content .admonition.seealso { background-color: var(--admonition-note-background-color); + border-radius: 4px; + box-shadow: 0px 3px 9px 0px rgb(0 0 0 / 29%); color: var(--admonition-note-color); } +.rst-content .admonition .admonition-title, .rst-content .admonition.note .admonition-title, .rst-content .admonition.seealso .admonition-title { background-color: var(--admonition-note-title-background-color); + border-radius: 4px 4px 0 0; color: var(--admonition-note-title-color); + font-weight: 600; + font-size: 105%; + line-height: 120%; + padding: 6px 16px; +} + +.rst-content .admonition .admonition-title:before { + margin-right: 9px; } .rst-content .admonition.attention, @@ -729,8 +1014,14 @@ code, color: var(--admonition-tip-title-color); } +.article-status strong { + color: var(--body-color); +} + /* Keyboard shortcuts tweaks */ -kbd, .kbd { +kbd, .kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > kbd, +.rst-content :not(dl.option-list) > :not(dt):not(kbd):not(.kbd) > .kbd { background-color: var(--kbd-background-color); border: 1px solid var(--kbd-outline-color); border-radius: 3px; @@ -753,6 +1044,193 @@ kbd.compound > .kbd, padding: 0; } +/* Class reference tweaks. */ + +.classref-section-separator { + border-color: var(--navbar-heading-color); + border-top-width: 3px; + margin: 36px 0; +} + +.classref-item-separator { + border-top-width: 2px; + margin: 26px 0; +} + +.classref-descriptions-group > p.classref-property, +.classref-descriptions-group > p.classref-signal, +.classref-descriptions-group > p.classref-annotation, +.classref-descriptions-group > p.classref-themeproperty, +.classref-descriptions-group > p.classref-method, +.classref-descriptions-group > p.classref-constructor, +.classref-descriptions-group > p.classref-operator, +.classref-descriptions-group > p.classref-constant, +.classref-descriptions-group > p.classref-enumeration, +.classref-descriptions-group > p.classref-enumeration-constant { + color: var(--classref-secondary-color); + font-family: var(--monospace-font-family); + font-size: 110%; + font-weight: 600; + margin-bottom: 18px; +} + +.classref-property { + margin-bottom: 12px; +} + +p + .classref-constant { + margin-top: 22px; +} + +.classref-descriptions-group > p.classref-enumeration-constant { + font-size: 100%; + margin-top: 18px; + margin-bottom: 14px; +} + +.classref-property > a, +.classref-signal > a, +.classref-annotation > a, +.classref-themeproperty > a, +.classref-method > a, +.classref-constructor > a, +.classref-operator > a, +.classref-constant > a, +.classref-enumeration > a { + opacity: 0.85; +} +.classref-enumeration-constant > a { + opacity: 0.75; +} + +.classref-property > a:hover, +.classref-signal > a:hover, +.classref-annotation > a:hover, +.classref-themeproperty > a:hover, +.classref-method > a:hover, +.classref-constructor > a:hover, +.classref-operator > a:hover, +.classref-constant > a:hover, +.classref-enumeration > a:hover, +.classref-enumeration-constant > a:hover { + opacity: 1; +} + +.classref-property > strong, +.classref-signal > strong, +.classref-annotation > strong, +.classref-themeproperty > strong, +.classref-method > strong, +.classref-constructor > strong, +.classref-operator > strong, +.classref-constant > strong, +.classref-enumeration > strong, +.classref-enumeration-constant > strong { + color: var(--classref-primary-color); +} + +.classref-property > code.literal, +.classref-signal > code.literal, +.classref-annotation > code.literal, +.classref-themeproperty > code.literal, +.classref-method > code.literal, +.classref-constructor > code.literal, +.classref-operator > code.literal, +.classref-constant > code.literal, +.classref-enumeration > code.literal, +.classref-enumeration-constant > code.literal { + background-color: transparent; + border: none; + padding: 0; + font-weight: 600; + font-size: 90% +} + +.classref-constant > code.literal, +.classref-enumeration-constant > code.literal { + color: var(--classref-setget-color); + font-weight: 400; +} + +/* Artificially increasing specificity to make it override theme.css. */ +.classref-descriptions-group ul.classref-property-setget { + color: var(--classref-setget-color); + font-size: 90%; + margin-bottom: 22px; +} + +.classref-property-setget > li { + line-height: 22px; +} + +.classref-property-setget p { + font-family: var(--monospace-font-family); + font-size: 100%; + line-height: 22px; +} + +.classref-property-setget p > a { + opacity: 0.75; +} +.classref-property-setget p > a:hover { + opacity: 1; +} + +.classref-property-setget p > strong { + color: var(--classref-setget-color); +} + +.classref-property-setget p > code { + background-color: transparent; + border: none; + padding: 0; + font-weight: 600; +} + +.classref-descriptions-group { + margin-left: 24px; +} +#enumerations.classref-descriptions-group { + margin-left: 48px; +} + +.classref-descriptions-group > h2, +.classref-descriptions-group > hr { + margin-left: -24px; +} +#enumerations.classref-descriptions-group > h2, +#enumerations.classref-descriptions-group > hr { + margin-left: -48px; +} + +.classref-descriptions-group > p { + margin-bottom: 12px; +} + +.classref-descriptions-group .classref-property, +.classref-descriptions-group .classref-signal, +.classref-descriptions-group .classref-annotation, +.classref-descriptions-group .classref-themeproperty, +.classref-descriptions-group .classref-method, +.classref-descriptions-group .classref-constructor, +.classref-descriptions-group .classref-operator, +.classref-descriptions-group .classref-constant, +.classref-descriptions-group .classref-enumeration-constant { + margin-left: -24px; +} + +.classref-descriptions-group .classref-enumeration { + margin-left: -48px; +} + +.classref-reftable-group .wy-table-responsive { + margin-bottom: 36px; +} + +.classref-reftable-group .wy-table-responsive > table { + width: 100%; +} + /* Buttons */ .btn-neutral { @@ -774,15 +1252,23 @@ kbd.compound > .kbd, opacity: var(--logo-opacity); } +.wy-side-nav-search > a { + padding: 0; + margin-bottom: 0.404em; + margin-top: 0.404em; +} + .wy-side-nav-search > a img.logo { /* Fixed size to prevent reflows and support hiDPI displays */ /* A 5 pixel margin is added on each side. The logo itself displays at 200×200 at 100% scaling. */ - width: 210px; - height: 210px; + width: 270px; + height: 70px; } .wy-side-nav-search { background-color: var(--navbar-background-color); + color: var(--navbar-level-1-color); + margin-right: 8px; } .wy-side-nav-search.fixed { @@ -834,7 +1320,22 @@ kbd.compound > .kbd, opacity: 0.55; } -/* Navigation bar */ +/* Version branch label below the logo */ +.wy-side-nav-search > div.version { + color: var(--navbar-dimmed-color); + font-size: 14px; + opacity: 0.9; +} + +/* Navigational top bar (mobile only) */ + +.wy-nav-top, +.wy-nav-top a { + background-color: var(--navbar-background-color); + color: var(--navbar-level-1-color); +} + +/* Navigational sidebar */ .wy-nav-side { background-color: var(--navbar-background-color); @@ -855,95 +1356,132 @@ kbd.compound > .kbd, letter-spacing: 0.75px; } -/* Mobile navigation */ +/* Default styling of navigation items */ -.wy-nav-top, -.wy-nav-top a { +.wy-menu-vertical li { background-color: var(--navbar-background-color); +} +.wy-menu-vertical li.current { + background-color: var(--navbar-current-background-color); +} + +.wy-menu-vertical li > a { color: var(--navbar-level-1-color); + font-size: 92%; + line-height: 20px; + padding: .4045em 1.618em; } - -/* Version branch label below the logo */ -.wy-side-nav-search > div.version { - color: var(--navbar-level-3-color); - opacity: 0.9; -} - -/* First level of navigation items */ - -.wy-menu-vertical a { - color: var(--navbar-level-1-color); -} - -.wy-menu-vertical a:hover { +.wy-menu-vertical li > a:hover { background-color: var(--navbar-background-color-hover); color: var(--navbar-level-1-color); } - -.wy-menu-vertical a:active { +.wy-menu-vertical li > a:active { background-color: var(--navbar-background-color-active); } -.wy-menu-vertical li.toctree-l1.current > a { - border: none; -} - -.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a button.toctree-expand, -.wy-menu-vertical li.toctree-l1 a button.toctree-expand, -.wy-menu-vertical li.toctree-l2 a button.toctree-expand { - color: var(--navbar-level-3-color); +.wy-menu-vertical li > a button.toctree-expand { + color: var(--navbar-expand-base-color) !important; opacity: 0.9; margin-right: 8px; -} -.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a:hover button.toctree-expand, -.wy-menu-vertical li.toctree-l1 a:hover button.toctree-expand, -.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand { - color: var(--navbar-level-2-color); + /* Make the expand icon a bit easier to hit. */ + position: relative; + width: 12px; + min-width: 12px; /* Forces the size to stay this way in the flexbox model. */ + height: 18px; +} +.wy-menu-vertical li.current > a button.toctree-expand { + color: var(--navbar-current-color) !important; +} +.wy-menu-vertical li > a:hover button.toctree-expand { + color: var(--navbar-expand-hover-color) !important; + opacity: 1; +} +.wy-menu-vertical li > a:active button.toctree-expand { + color: var(--navbar-expand-active-color) !important; opacity: 1; } -.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a:active button.toctree-expand, -.wy-menu-vertical li.toctree-l1 a:active button.toctree-expand, -.wy-menu-vertical li.toctree-l2 a:active button.toctree-expand { - color: var(--navbar-level-1-color); - opacity: 1; +/* Make the expand icon a bit easier to hit. */ +.wy-menu-vertical li > a button.toctree-expand:before { + position: absolute; + top: -2px; + left: -6px; + width: 24px; + height: 24px; + padding: 6px; } -/* Second (and higher) levels of navigation items */ +.wy-menu-vertical li.current > a, +.wy-menu-vertical li.toctree-l2.current > a { + background-color: var(--navbar-current-background-color-hover); + border-bottom: 2px solid var(--navbar-current-background-color); + color: var(--navbar-current-color); + font-weight: 600; -.wy-menu-vertical li.current a { /* Make long words always display on a single line, keep wrapping for multiple words */ /* This fixes the class reference titles' display with very long class names */ display: flex; } - -.wy-menu-vertical li.current a, -.wy-menu-vertical li.toctree-l2.current > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, -.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { - background-color: var(--navbar-current-background-color); - color: var(--navbar-level-2-color); - border-color: var(--navbar-current-background-color); -} - -.wy-menu-vertical li.current a:hover, -.wy-menu-vertical li.toctree-l2.current > a:hover, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, -.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:hover { +.wy-menu-vertical li.current > a:hover, +.wy-menu-vertical li.toctree-l2.current > a:hover { background-color: var(--navbar-current-background-color-hover); } - -.wy-menu-vertical li.current a:active, -.wy-menu-vertical li.toctree-l2.current > a:active, -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, -.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:active { +.wy-menu-vertical li.current > a:active, +.wy-menu-vertical li.toctree-l2.current > a:active { background-color: var(--navbar-current-background-color-active); } -.wy-menu-vertical a { - /* This overrides 8px margin added in other multi-selector rules */ - margin-right: 0; +/* Slightly adjust first level items. */ +.wy-menu-vertical li.toctree-l1 > a, +.wy-menu-vertical li.toctree-l1.current > a { + border: none; + padding: .4045em 1.918em; +} +.wy-menu-vertical li.toctree-l1.current > a { + border-bottom: 2px solid var(--navbar-current-background-color); +} + +/* Override styling for children of the current item. */ +.wy-menu-vertical li.current li > a, +.wy-menu-vertical li.toctree-l2.current li > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { + background-color: var(--navbar-current-background-color); + border: none; + border-bottom: 2px solid var(--navbar-current-background-color); + color: var(--navbar-level-2-color); +} +.wy-menu-vertical li.current li > a:hover, +.wy-menu-vertical li.toctree-l2.current li > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:hover { + background-color: var(--navbar-current-background-color-hover); +} +.wy-menu-vertical li.current li > a:active, +.wy-menu-vertical li.toctree-l2.current li > a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:active { + background-color: var(--navbar-current-background-color-active); +} + +.wy-menu-vertical li.toctree-l2.current li > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a { + color: var(--navbar-level-3-color); +} +.wy-menu-vertical li.toctree-l2.current li > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a:hover { + color: var(--navbar-level-1-color); +} + +.wy-menu-vertical li.current li.current > a, +.wy-menu-vertical li.toctree-l2.current li.current > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > a, +.wy-menu-vertical li.toctree-l2.current li.toctree-l4.current > a { + color: var(--navbar-current-color); + font-weight: 600; } /* Banner panel in sidebar */ @@ -951,12 +1489,27 @@ kbd.compound > .kbd, position: fixed; } -/* Version selector (only visible on Read the Docs) */ +/* Read the Docs flyout panel, with language and version selectors. */ .rst-versions { background-color: var(--navbar-current-background-color); } +.rst-versions.shift-up { + overflow: visible; +} + +.rst-versions.shift-up:before { + content: ''; + position: absolute; + left: 0; + top: -8px; + width: 100%; + height: 8px; + pointer-events: none; + background: linear-gradient(transparent, hsla(0, 0%, 0%, 0.2)); +} + @media only screen and (min-width: 769px) { .rst-versions { /* Required to center the page on wide displays */ @@ -971,36 +1524,67 @@ kbd.compound > .kbd, color: var(--navbar-level-1-color); } -.rst-versions .rst-other-versions small { - color: var(--navbar-level-3-color); -} - -.rst-versions .rst-other-versions dd a:hover { - text-decoration: underline; +.rst-versions .rst-current-version, +.rst-versions .rst-other-versions { + padding: 12px 14px; } .rst-versions .rst-other-versions { color: var(--navbar-heading-color); } -.rst-versions .rst-current-version { - background-color: var(--navbar-current-background-color); +.rst-versions .rst-other-versions dl + dl { + margin-top: 4px; } +.rst-versions .rst-other-versions hr { + border-color: var(--hr-color); + margin: 12px 0; +} + +.rst-versions .rst-other-versions small { + color: var(--navbar-dimmed-color); +} + +.rst-versions .rst-other-versions dd a:hover { + text-decoration: underline; +} + +/* This will hide every segment of the panel, starting with the 4th. */ +.rst-versions .rst-other-versions .injected dl:nth-child(n+4) { + display: none; +} + +.rst-versions .rst-current-version { + background-color: var(--navbar-current-background-color); + border-bottom: 1px solid var(--hr-color); +} .rst-versions .rst-current-version:hover { background-color: var(--navbar-current-background-color-hover); } - .rst-versions .rst-current-version:active { background-color: var(--navbar-current-background-color-active); } -/* Hide the obnoxious automatic highlight in search results */ +.rst-versions .rst-current-version .fa { + line-height: 20px; +} + +/* Hide the obnoxious automatic highlight from the search context. */ .rst-content .highlighted { background-color: transparent; + box-shadow: none; font-weight: inherit; padding: 0; } +/* Still slightly highlight matched parts on the dedicated search results page. */ +.rst-content #search-results .highlighted { + background-color: var(--search-highlighted-color); + border-radius: 2px; + color: var(--body-color); + font-weight: 600; + padding: 0 3px; +} /* Allows the scrollbar to be shown in the sidebar */ @media only screen and (min-width: 769px) { @@ -1017,6 +1601,7 @@ kbd.compound > .kbd, overflow-y: auto; overflow-x: hidden; max-height: calc(100% - 348px); + padding-bottom: 24px; } @media screen and (max-width: 768px) { .wy-nav-side { @@ -1048,3 +1633,44 @@ kbd.compound > .kbd, .wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:active { background-color: var(--navbar-scrollbar-active-color); } + +/* Allows to add a green or red bar to code blocks for "good"/"bad" code examples. */ +.code-example-good div.highlight { + border-left-color: var(--code-example-good-color); + border-left-width: 8px; +} +.code-example-bad div.highlight { + border-left-color: var(--code-example-bad-color); + border-left-width: 8px; +} + +/* Togglable sidebar sections. */ +.wy-menu-vertical p.caption { + cursor: pointer; +} +.wy-menu-vertical p.caption.active { + background-color: var(--navbar-category-active-color); +} +.wy-menu-vertical p.caption:hover { + background-color: var(--navbar-background-color-hover); +} + +.wy-menu-vertical p.caption.active .caption-text:before { + transform: rotate(90deg); +} +.wy-menu-vertical p.caption .caption-text:before { + content: "❯"; + display: inline-block; + margin-left: -4px; + transition: transform 0.2s; + width: 16px; + height: 32px; + transform-origin: 2px 16px; +} + +.wy-menu-vertical p.caption + ul { + display: none; +} +.wy-menu-vertical p.caption + ul.active { + display: block; +} diff --git a/_static/css/dev.css b/_static/css/dev.css new file mode 100644 index 000000000..87ad1d310 --- /dev/null +++ b/_static/css/dev.css @@ -0,0 +1,8 @@ +/** + * CSS tweaks that are only added outside ReadTheDocs (i.e. when built locally). + */ + +/* Re-add default red boxes around Pygments errors */ +.highlight .err { + border: 1px solid #FF0000; +} diff --git a/_static/css/fonts/JetBrainsMono-Bold.woff2 b/_static/css/fonts/JetBrainsMono-Bold.woff2 new file mode 100644 index 000000000..023512c05 Binary files /dev/null and b/_static/css/fonts/JetBrainsMono-Bold.woff2 differ diff --git a/_static/css/fonts/JetBrainsMono-Medium.woff2 b/_static/css/fonts/JetBrainsMono-Medium.woff2 new file mode 100644 index 000000000..484c9e641 Binary files /dev/null and b/_static/css/fonts/JetBrainsMono-Medium.woff2 differ diff --git a/_static/css/fonts/JetBrainsMono-Regular.woff2 b/_static/css/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 000000000..8c862e334 Binary files /dev/null and b/_static/css/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/_static/js/custom.js b/_static/js/custom.js index f97f68404..7479bb37d 100644 --- a/_static/js/custom.js +++ b/_static/js/custom.js @@ -1,3 +1,4 @@ + // Handle page scroll and adjust sidebar accordingly. // Each page has two scrolls: the main scroll, which is moving the content of the page; @@ -7,207 +8,398 @@ // available to the navigation on the fly. There is also a banner below the navigation // that must be dealt with simultaneously. const registerOnScrollEvent = (function(){ - // Configuration. + // Configuration. - // The number of pixels the user must scroll by before the logo is completely hidden. - const scrollTopPixels = 234; - // The target margin to be applied to the navigation bar when the logo is hidden. - const menuTopMargin = 90; - // The max-height offset when the logo is completely visible. - const menuHeightOffset_default = 338; - // The max-height offset when the logo is completely hidden. - const menuHeightOffset_fixed = 102; - // The distance between the two max-height offset values above; used for intermediate values. - const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); + // The number of pixels the user must scroll by before the logo is completely hidden. + const scrollTopPixels = 84; + // The target margin to be applied to the navigation bar when the logo is hidden. + const menuTopMargin = 70; + // The max-height offset when the logo is completely visible. + const menuHeightOffset_default = 162; + // The max-height offset when the logo is completely hidden. + const menuHeightOffset_fixed = 80; + // The distance between the two max-height offset values above; used for intermediate values. + const menuHeightOffset_diff = (menuHeightOffset_default - menuHeightOffset_fixed); - // Media query handler. - return function(mediaQuery) { - // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). - // This handler is executed when the result of the query evaluation changes, which means that - // the page has moved between "desktop" and "mobile" states. + // Media query handler. + return function(mediaQuery) { + // We only apply this logic to the "desktop" resolution (defined by a media query at the bottom). + // This handler is executed when the result of the query evaluation changes, which means that + // the page has moved between "desktop" and "mobile" states. - // When entering the "desktop" state, we register scroll events and adjust elements on the page. - // When entering the "mobile" state, we clean up any registered events and restore elements on the page - // to their initial state. + // When entering the "desktop" state, we register scroll events and adjust elements on the page. + // When entering the "mobile" state, we clean up any registered events and restore elements on the page + // to their initial state. - const $window = $(window); - const $sidebar = $('.wy-side-scroll'); - const $search = $sidebar.children('.wy-side-nav-search'); - const $menu = $sidebar.children('.wy-menu-vertical'); - const $ethical = $sidebar.children('.ethical-rtd'); + const $window = $(window); + const $sidebar = $('.wy-side-scroll'); + const $search = $sidebar.children('.wy-side-nav-search'); + const $menu = $sidebar.children('.wy-menu-vertical'); + const $ethical = $sidebar.children('.ethical-rtd'); - // This padding is needed to correctly adjust the height of the scrollable area in the sidebar. - // It has to have the same height as the ethical block, if there is one. - let $menuPadding = $menu.children('.wy-menu-ethical-padding'); - if ($menuPadding.length == 0) { - $menuPadding = $('
'); - $menu.append($menuPadding); - } - - if (mediaQuery.matches) { - // Entering the "desktop" state. - - // The main scroll event handler. - // Executed as the page is scrolled and once immediatelly as the page enters this state. - const handleMainScroll = (currentScroll) => { - if (currentScroll >= scrollTopPixels) { - // After the page is scrolled below the threshold, we fix everything in place. - $search.css('margin-top', `-${scrollTopPixels}px`); - $menu.css('margin-top', `${menuTopMargin}px`); - $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); - } - else { - // Between the top of the page and the threshold we calculate intermediate values - // to guarantee a smooth transition. - $search.css('margin-top', `-${currentScroll}px`); - $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); - - if (currentScroll > 0) { - const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; - const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; - $menu.css('max-height', `calc(100% - ${offsetValue}px)`); - } else { - $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); - } - } - }; - - // The sidebar scroll event handler. - // Executed as the sidebar is scrolled as well as after the main scroll. This is needed - // because the main scroll can affect the scrollable area of the sidebar. - const handleSidebarScroll = () => { - const menuElement = $menu.get(0); - const menuScrollTop = $menu.scrollTop(); - const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); - - // As the navigation is scrolled we add a shadow to the top bar hanging over it. - if (menuScrollTop > 0) { - $search.addClass('fixed-and-scrolled'); - } else { - $search.removeClass('fixed-and-scrolled'); - } - - // Near the bottom we start moving the sidebar banner into view. - if (menuScrollBottom < ethicalOffsetBottom) { - $ethical.css('display', 'block'); - $ethical.css('margin-top', `-${ethicalOffsetBottom - menuScrollBottom}px`); - } else { - $ethical.css('display', 'none'); - $ethical.css('margin-top', '0px'); - } - }; - - $search.addClass('fixed'); - $ethical.addClass('fixed'); - - // Adjust the inner height of navigation so that the banner can be overlaid there later. - const ethicalOffsetBottom = $ethical.height() || 0; - if (ethicalOffsetBottom) { - $menuPadding.css('height', `${ethicalOffsetBottom}px`); - } else { - $menuPadding.css('height', `0px`); + // This padding is needed to correctly adjust the height of the scrollable area in the sidebar. + // It has to have the same height as the ethical block, if there is one. + let $menuPadding = $menu.children('.wy-menu-ethical-padding'); + if ($menuPadding.length == 0) { + $menuPadding = $('
'); + $menu.append($menuPadding); } - $window.scroll(function() { + if (mediaQuery.matches) { + // Entering the "desktop" state. + + // The main scroll event handler. + // Executed as the page is scrolled and once immediately as the page enters this state. + const handleMainScroll = (currentScroll) => { + if (currentScroll >= scrollTopPixels) { + // After the page is scrolled below the threshold, we fix everything in place. + $search.css('margin-top', `-${scrollTopPixels}px`); + $menu.css('margin-top', `${menuTopMargin}px`); + $menu.css('max-height', `calc(100% - ${menuHeightOffset_fixed}px)`); + } + else { + // Between the top of the page and the threshold we calculate intermediate values + // to guarantee a smooth transition. + $search.css('margin-top', `-${currentScroll}px`); + $menu.css('margin-top', `${menuTopMargin + (scrollTopPixels - currentScroll)}px`); + + if (currentScroll > 0) { + const scrolledPercent = (scrollTopPixels - currentScroll) / scrollTopPixels; + const offsetValue = menuHeightOffset_fixed + menuHeightOffset_diff * scrolledPercent; + $menu.css('max-height', `calc(100% - ${offsetValue}px)`); + } else { + $menu.css('max-height', `calc(100% - ${menuHeightOffset_default}px)`); + } + } + }; + + // The sidebar scroll event handler. + // Executed as the sidebar is scrolled as well as after the main scroll. This is needed + // because the main scroll can affect the scrollable area of the sidebar. + const handleSidebarScroll = () => { + const menuElement = $menu.get(0); + const menuScrollTop = $menu.scrollTop(); + const menuScrollBottom = menuElement.scrollHeight - (menuScrollTop + menuElement.offsetHeight); + + // As the navigation is scrolled we add a shadow to the top bar hanging over it. + if (menuScrollTop > 0) { + $search.addClass('fixed-and-scrolled'); + } else { + $search.removeClass('fixed-and-scrolled'); + } + + // Near the bottom we start moving the sidebar banner into view. + if (menuScrollBottom < ethicalOffsetBottom) { + $ethical.css('display', 'block'); + $ethical.css('margin-top', `-${ethicalOffsetBottom - menuScrollBottom}px`); + } else { + $ethical.css('display', 'none'); + $ethical.css('margin-top', '0px'); + } + }; + + $search.addClass('fixed'); + $ethical.addClass('fixed'); + + // Adjust the inner height of navigation so that the banner can be overlaid there later. + const ethicalOffsetBottom = $ethical.height() || 0; + if (ethicalOffsetBottom) { + $menuPadding.css('height', `${ethicalOffsetBottom}px`); + } else { + $menuPadding.css('height', `0px`); + } + + $window.scroll(function() { + handleMainScroll(window.scrollY); + handleSidebarScroll(); + }); + + $menu.scroll(function() { + handleSidebarScroll(); + }); + handleMainScroll(window.scrollY); handleSidebarScroll(); - }); + } else { + // Entering the "mobile" state. - $menu.scroll(function() { - handleSidebarScroll(); - }); + $window.unbind('scroll'); + $menu.unbind('scroll'); - handleMainScroll(window.scrollY); - handleSidebarScroll(); - } else { - // Entering the "mobile" state. + $search.removeClass('fixed'); + $ethical.removeClass('fixed'); - $window.unbind('scroll'); - $menu.unbind('scroll'); - - $search.removeClass('fixed'); - $ethical.removeClass('fixed'); - - $search.css('margin-top', `0px`); - $menu.css('margin-top', `0px`); - $menu.css('max-height', 'initial'); - $menuPadding.css('height', `0px`); - $ethical.css('margin-top', '0px'); - $ethical.css('display', 'block'); - } - }; -})(); - -// Subscribe to DOM changes in the sidebar container, because there is a -// banner that gets added at a later point, that we might not catch otherwise. -const registerSidebarObserver = (function(){ - return function(callback) { - const sidebarContainer = document.querySelector('.wy-side-scroll'); - - let sidebarEthical = null; - const registerEthicalObserver = () => { - if (sidebarEthical) { - // Do it only once. - return; + $search.css('margin-top', `0px`); + $menu.css('margin-top', `0px`); + $menu.css('max-height', 'initial'); + $menuPadding.css('height', `0px`); + $ethical.css('margin-top', '0px'); + $ethical.css('display', 'block'); } + }; + })(); - sidebarEthical = sidebarContainer.querySelector('.ethical-rtd'); - if (!sidebarEthical) { - // Do it only after we have the element there. - return; - } + // Subscribe to DOM changes in the sidebar container, because there is a + // banner that gets added at a later point, that we might not catch otherwise. + const registerSidebarObserver = (function(){ + return function(callback) { + const sidebarContainer = document.querySelector('.wy-side-scroll'); - // This observer watches over the ethical block in sidebar, and all of its subtree. - const ethicalObserverConfig = { childList: true, subtree: true }; - const ethicalObserverCallback = (mutationsList, observer) => { + let sidebarEthical = null; + const registerEthicalObserver = () => { + if (sidebarEthical) { + // Do it only once. + return; + } + + sidebarEthical = sidebarContainer.querySelector('.ethical-rtd'); + if (!sidebarEthical) { + // Do it only after we have the element there. + return; + } + + // This observer watches over the ethical block in sidebar, and all of its subtree. + const ethicalObserverConfig = { childList: true, subtree: true }; + const ethicalObserverCallback = (mutationsList, observer) => { + for (let mutation of mutationsList) { + if (mutation.type !== 'childList') { + continue; + } + + callback(); + } + }; + + const ethicalObserver = new MutationObserver(ethicalObserverCallback); + ethicalObserver.observe(sidebarEthical, ethicalObserverConfig); + }; + registerEthicalObserver(); + + // This observer watches over direct children of the main sidebar container. + const observerConfig = { childList: true }; + const observerCallback = (mutationsList, observer) => { for (let mutation of mutationsList) { if (mutation.type !== 'childList') { continue; } callback(); + registerEthicalObserver(); } }; - const ethicalObserver = new MutationObserver(ethicalObserverCallback); - ethicalObserver.observe(sidebarEthical, ethicalObserverConfig); - }; - registerEthicalObserver(); + const observer = new MutationObserver(observerCallback); + observer.observe(sidebarContainer, observerConfig); - // This observer watches over direct children of the main sidebar container. - const observerConfig = { childList: true }; - const observerCallback = (mutationsList, observer) => { - for (let mutation of mutationsList) { - if (mutation.type !== 'childList') { - continue; + // Default TOC tree has links that immediately navigate to the selected page. Our + // theme adds an extra button to fold and unfold the tree without navigating away. + // But that means that the buttons are added after the initial load, so we need to + // improvise to detect clicks on these buttons. + const scrollElement = document.querySelector('.wy-menu-vertical'); + const registerLinkHandler = (linkChildren) => { + linkChildren.forEach(it => { + if (it.nodeType === Node.ELEMENT_NODE && it.classList.contains('toctree-expand')) { + it.addEventListener('click', () => { + // Toggling a different item will close the currently opened one, + // which may shift the clicked item out of the view. We correct for that. + const menuItem = it.parentNode; + const baseScrollOffset = scrollElement.scrollTop + scrollElement.offsetTop; + const maxScrollOffset = baseScrollOffset + scrollElement.offsetHeight; + + if (menuItem.offsetTop < baseScrollOffset || menuItem.offsetTop > maxScrollOffset) { + menuItem.scrollIntoView(); + } + + callback(); + }); + } + }); + } + + const navigationSections = document.querySelectorAll('.wy-menu-vertical ul'); + navigationSections.forEach(it => { + if (it.previousSibling == null || typeof it.previousSibling === 'undefined' || it.previousSibling.tagName != 'A') { + return; } - callback(); - registerEthicalObserver(); - } + const navigationLink = it.previousSibling; + registerLinkHandler(navigationLink.childNodes); + + const linkObserverConfig = { childList: true }; + const linkObserverCallback = (mutationsList, observer) => { + for (let mutation of mutationsList) { + registerLinkHandler(mutation.addedNodes); + } + }; + + const linkObserver = new MutationObserver(linkObserverCallback); + linkObserver.observe(navigationLink, linkObserverConfig); + }); }; + })(); - const observer = new MutationObserver(observerCallback); - observer.observe(sidebarContainer, observerConfig); - }; -})(); + $(document).ready(() => { + // Remove the search match highlights from the page, and adjust the URL in the + // navigation history. + const url = new URL(location.href); + if (url.searchParams.has('highlight')) { + Documentation.hideSearchWords(); + } -$(document).ready(() => { - const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); + // Initialize handlers for page scrolling and our custom sidebar. + const mediaQuery = window.matchMedia('only screen and (min-width: 769px)'); - registerOnScrollEvent(mediaQuery); - mediaQuery.addListener(registerOnScrollEvent); - - registerSidebarObserver(() => { registerOnScrollEvent(mediaQuery); + mediaQuery.addListener(registerOnScrollEvent); + + registerSidebarObserver(() => { + registerOnScrollEvent(mediaQuery); + }); + + // Add line-break suggestions to the sidebar navigation items in the class reference section. + // + // Some class reference pages have very long PascalCase names, such as + // VisualShaderNodeCurveXYZTexture + // Those create issues for our layout, as we can neither make them wrap with CSS without + // breaking normal article titles, nor is it good to have them overflow their containers. + // So we use a tag to insert mid-word suggestions for appropriate splits, so the browser + // knows that it's okay to split it like + // Visual Shader Node Curve XYZTexture + // and add a new line at an opportune moment. + const classReferenceLinks = document.querySelectorAll('.wy-menu-vertical > ul:last-of-type .reference.internal'); + for (const linkItem of classReferenceLinks) { + let textNode = null; + linkItem.childNodes.forEach(it => { + if (it.nodeType === Node.TEXT_NODE) { + // If this is a text node and if it needs to be updated, store a reference. + let text = it.textContent; + if (!(text.includes(" ") || text.length < 10)) { + textNode = it; + } + } + }); + + if (textNode != null) { + let text = textNode.textContent; + // Add suggested line-breaks and replace the original text. + // The regex looks for a lowercase letter followed by a number or an uppercase + // letter. We avoid splitting at the last character in the name, though. + text = text.replace(/([a-z])([A-Z0-9](?!$))/gm, '$1$2'); + + linkItem.removeChild(textNode); + linkItem.insertAdjacentHTML('beforeend', text); + } + } + + // See `godot_is_latest` in conf.py + const isLatest = document.querySelector('meta[name=doc_is_latest]').content.toLowerCase() === 'true'; + if (isLatest) { + // Add a compatibility notice using JavaScript so it doesn't end up in the + // automatically generated `meta description` tag. + + const baseUrl = [location.protocol, '//', location.host, location.pathname].join(''); + // These lines only work as expected in the production environment, can't test this locally. + const fallbackUrl = baseUrl.replace('/latest/', '/stable/'); + const homeUrl = baseUrl.split('/latest/')[0] + '/stable/'; + const searchUrl = homeUrl + 'search.html?q='; + + const noticeLink = document.querySelector('.latest-notice-link'); + + // Insert a placeholder to display as we're making a request. + noticeLink.innerHTML = ` + Checking the stable version + of the documentation... + `; + + // Make a HEAD request to the possible stable URL to check if the page exists. + fetch(fallbackUrl, { method: 'HEAD' }) + .then((res) => { + // We only check the HTTP status, which should tell us if the link is valid or not. + if (res.status === 200) { + noticeLink.innerHTML = ` + See the stable version + of this documentation page instead. + `; + } else { + // Err, just to fallthrough to catch. + throw Error('Bad request'); + } + }) + .catch((err) => { + let message = ` + This page does not exist in the stable version + of the documentation. + `; + + // Also suggest a search query using the page's title. It should work with translations as well. + // Note that we can't use the title tag as it has a permanent suffix. OG title doesn't, though. + const titleMeta = document.querySelector('meta[property="og:title"]'); + if (typeof titleMeta !== 'undefined') { + const pageTitle = titleMeta.getAttribute('content'); + message += ` + You can try searching for "${pageTitle}" instead. + `; + } + + noticeLink.innerHTML = message; + }); + } + + // Load instant.page to prefetch pages upon hovering. This makes navigation feel + // snappier. The script is dynamically appended as Read the Docs doesn't have + // a way to add scripts with a "module" attribute. + const instantPageScript = document.createElement('script'); + instantPageScript.toggleAttribute('module'); + /*! instant.page v5.1.0 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */ + instantPageScript.innerText = 'let t,e;const n=new Set,o=document.createElement("link"),i=o.relList&&o.relList.supports&&o.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype,s="instantAllowQueryString"in document.body.dataset,a="instantAllowExternalLinks"in document.body.dataset,r="instantWhitelist"in document.body.dataset,c="instantMousedownShortcut"in document.body.dataset,d=1111;let l=65,u=!1,f=!1,m=!1;if("instantIntensity"in document.body.dataset){const t=document.body.dataset.instantIntensity;if("mousedown"==t.substr(0,"mousedown".length))u=!0,"mousedown-only"==t&&(f=!0);else if("viewport"==t.substr(0,"viewport".length))navigator.connection&&(navigator.connection.saveData||navigator.connection.effectiveType&&navigator.connection.effectiveType.includes("2g"))||("viewport"==t?document.documentElement.clientWidth*document.documentElement.clientHeight<45e4&&(m=!0):"viewport-all"==t&&(m=!0));else{const e=parseInt(t);isNaN(e)||(l=e)}}if(i){const n={capture:!0,passive:!0};if(f||document.addEventListener("touchstart",function(t){e=performance.now();const n=t.target.closest("a");if(!h(n))return;v(n.href)},n),u?c||document.addEventListener("mousedown",function(t){const e=t.target.closest("a");if(!h(e))return;v(e.href)},n):document.addEventListener("mouseover",function(n){if(performance.now()-e{v(o.href),t=void 0},l)},n),c&&document.addEventListener("mousedown",function(t){if(performance.now()-e1||t.metaKey||t.ctrlKey)return;if(!n)return;n.addEventListener("click",function(t){1337!=t.detail&&t.preventDefault()},{capture:!0,passive:!1,once:!0});const o=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!1,detail:1337});n.dispatchEvent(o)},n),m){let t;(t=window.requestIdleCallback?t=>{requestIdleCallback(t,{timeout:1500})}:t=>{t()})(()=>{const t=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){const n=e.target;t.unobserve(n),v(n.href)}})});document.querySelectorAll("a").forEach(e=>{h(e)&&t.observe(e)})})}}function p(e){e.relatedTarget&&e.target.closest("a")==e.relatedTarget.closest("a")||t&&(clearTimeout(t),t=void 0)}function h(t){if(t&&t.href&&(!r||"instant"in t.dataset)&&(a||t.origin==location.origin||"instant"in t.dataset)&&["http:","https:"].includes(t.protocol)&&("http:"!=t.protocol||"https:"!=location.protocol)&&(s||!t.search||"instant"in t.dataset)&&!(t.hash&&t.pathname+t.search==location.pathname+location.search||"noInstant"in t.dataset))return!0}function v(t){if(n.has(t))return;const e=document.createElement("link");e.rel="prefetch",e.href=t,document.head.appendChild(e),n.add(t)}'; + document.head.appendChild(instantPageScript); + + // Make sections in the sidebar togglable. + let hasCurrent = false; + let menuHeaders = document.querySelectorAll('.wy-menu-vertical .caption[role=heading]'); + menuHeaders.forEach(it => { + let connectedMenu = it.nextElementSibling; + + // Enable toggling. + it.addEventListener('click', () => { + if (connectedMenu.classList.contains('active')) { + connectedMenu.classList.remove('active'); + it.classList.remove('active'); + } else { + connectedMenu.classList.add('active'); + it.classList.add('active'); + } + + // Hide other sections. + menuHeaders.forEach(ot => { + if (ot !== it && ot.classList.contains('active')) { + ot.nextElementSibling.classList.remove('active'); + ot.classList.remove('active'); + } + }); + + registerOnScrollEvent(mediaQuery); + }, true); + + // Set the default state, expand our current section. + if (connectedMenu.classList.contains('current')) { + connectedMenu.classList.add('active'); + it.classList.add('active'); + + hasCurrent = true; + } + }); + + // Unfold the first (general information) section on the home page. + if (!hasCurrent && menuHeaders.length > 0) { + menuHeaders[0].classList.add('active'); + menuHeaders[0].nextElementSibling.classList.add('active'); + + registerOnScrollEvent(mediaQuery); + } }); - // Load instant.page to prefetch pages upon hovering. This makes navigation feel - // snappier. The script is dynamically appended as Read the Docs doesn't have - // a way to add scripts with a "module" attribute. - const instantPageScript = document.createElement('script'); - instantPageScript.toggleAttribute('module'); - /*! instant.page v5.1.0 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */ - instantPageScript.innerText = 'let t,e;const n=new Set,o=document.createElement("link"),i=o.relList&&o.relList.supports&&o.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype,s="instantAllowQueryString"in document.body.dataset,a="instantAllowExternalLinks"in document.body.dataset,r="instantWhitelist"in document.body.dataset,c="instantMousedownShortcut"in document.body.dataset,d=1111;let l=65,u=!1,f=!1,m=!1;if("instantIntensity"in document.body.dataset){const t=document.body.dataset.instantIntensity;if("mousedown"==t.substr(0,"mousedown".length))u=!0,"mousedown-only"==t&&(f=!0);else if("viewport"==t.substr(0,"viewport".length))navigator.connection&&(navigator.connection.saveData||navigator.connection.effectiveType&&navigator.connection.effectiveType.includes("2g"))||("viewport"==t?document.documentElement.clientWidth*document.documentElement.clientHeight<45e4&&(m=!0):"viewport-all"==t&&(m=!0));else{const e=parseInt(t);isNaN(e)||(l=e)}}if(i){const n={capture:!0,passive:!0};if(f||document.addEventListener("touchstart",function(t){e=performance.now();const n=t.target.closest("a");if(!h(n))return;v(n.href)},n),u?c||document.addEventListener("mousedown",function(t){const e=t.target.closest("a");if(!h(e))return;v(e.href)},n):document.addEventListener("mouseover",function(n){if(performance.now()-e{v(o.href),t=void 0},l)},n),c&&document.addEventListener("mousedown",function(t){if(performance.now()-e1||t.metaKey||t.ctrlKey)return;if(!n)return;n.addEventListener("click",function(t){1337!=t.detail&&t.preventDefault()},{capture:!0,passive:!1,once:!0});const o=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!1,detail:1337});n.dispatchEvent(o)},n),m){let t;(t=window.requestIdleCallback?t=>{requestIdleCallback(t,{timeout:1500})}:t=>{t()})(()=>{const t=new IntersectionObserver(e=>{e.forEach(e=>{if(e.isIntersecting){const n=e.target;t.unobserve(n),v(n.href)}})});document.querySelectorAll("a").forEach(e=>{h(e)&&t.observe(e)})})}}function p(e){e.relatedTarget&&e.target.closest("a")==e.relatedTarget.closest("a")||t&&(clearTimeout(t),t=void 0)}function h(t){if(t&&t.href&&(!r||"instant"in t.dataset)&&(a||t.origin==location.origin||"instant"in t.dataset)&&["http:","https:"].includes(t.protocol)&&("http:"!=t.protocol||"https:"!=location.protocol)&&(s||!t.search||"instant"in t.dataset)&&!(t.hash&&t.pathname+t.search==location.pathname+location.search||"noInstant"in t.dataset))return!0}function v(t){if(n.has(t))return;const e=document.createElement("link");e.rel="prefetch",e.href=t,document.head.appendChild(e),n.add(t)}'; - document.head.appendChild(instantPageScript); -}); + // Override the default implementation from doctools.js to avoid this behavior. + Documentation.highlightSearchWords = function() { + // Nope. + } diff --git a/_templates/breadcrumbs.html b/_templates/breadcrumbs.html index 0a60a7a1f..d7e3dfd38 100644 --- a/_templates/breadcrumbs.html +++ b/_templates/breadcrumbs.html @@ -1,24 +1,40 @@ {%- extends "sphinx_rtd_theme/breadcrumbs.html" %} +{% block breadcrumbs %} +
  • +
    + {{ godot_docs_title | replace("%s", godot_version) }} +
    +
      + {{ super() }} +
    +
  • +{% endblock %} + {% block breadcrumbs_aside %} {% if not meta or meta.get('github_url') != 'hide' %} -{{ super() }} +
  • +
      + {{ super() }} +
    - - - Learn how to contribute! - + + @media screen and (max-width: 480px) { + .godot-edit-guidelines { + display: none; + } + } + + + Learn how to contribute! + +
  • {% endif %} {% endblock %} diff --git a/_templates/layout.html b/_templates/layout.html index fdec13a7b..268c4ca38 100644 --- a/_templates/layout.html +++ b/_templates/layout.html @@ -1,4 +1,15 @@ {% extends "!layout.html" -%} +{# Refer to https://github.com/readthedocs/sphinx_rtd_theme/blob/master/sphinx_rtd_theme/layout.html #} + +{% block htmltitle -%} +{{ godot_title_prefix }}{{ title|striptags|e }}{{ titlesuffix }} +{% endblock -%} + +{% block extrahead -%} + + +{% endblock -%} + {% block linktags -%} {% if godot_inject_language_links -%} @@ -14,6 +25,52 @@ {{ super() }} {% endblock -%} -{% block htmltitle -%} -{{ godot_title_prefix }}{{ title|striptags|e }}{{ titlesuffix }} -{% endblock -%} +{%- block document %} +
    + {% if godot_is_latest or godot_show_article_status %} +
    + {% if godot_is_latest %} +
    +

    Attention: Here be dragons

    +

    + This is the latest + (unstable) version of this documentation, which may document features + not available in or compatible with released stable versions of Godot. +

    + +
    + {% endif %} + + {% if godot_show_article_status and not godot_is_latest %} +
    + {% if meta and meta.get('article_outdated') == 'True' %} +

    Work in progress

    +

    + The content of this page was not yet updated for Godot + {{ godot_version }} + and may be outdated. If you know how to improve this page or you can confirm + that it's up to date, feel free to open a pull request. +

    + {% else %} +

    Up to date

    +

    + This page is up to date for Godot {{ godot_version }}. + If you still find outdated information, please open an issue. +

    + {% endif %} +
    + {% endif %} +
    + {% endif %} + + {% block body %}{% endblock %} +
    +{%- if self.comments()|trim %} +
    + {%- block comments %}{% endblock %} +
    +{%- endif%} + +{%- endblock %} diff --git a/_templates/versions.html b/_templates/versions.html new file mode 100644 index 000000000..e46ca819a --- /dev/null +++ b/_templates/versions.html @@ -0,0 +1,60 @@ +{# Add rst-badge after rst-versions for small badge style. #} +{% set display_version = version -%} +{% set listed_languages = ({"en":"#", "de":"#", "es":"#", "fr":"#"}).items() -%} +{% set listed_versions = ({"stable":"#", "latest":"#"}).items() -%} + +{% if READTHEDOCS and current_version %} + {% set display_version = current_version -%} +{% endif %} +{% if READTHEDOCS and versions %} + {% set listed_versions = versions -%} +{% endif %} + +
    + + Read the Docs + v: {{ display_version }}{% if display_version != godot_version %} ({{ godot_version }}){% endif %} + + +
    + {# + The contents of this element will be replaced in production. + But we can still have some mock data for testing. + #} + +
    +
    {{ _('Languages') }}
    + {% for slug, url in listed_languages %} +
    {{ slug }}
    + {% endfor %} +
    +
    +
    {{ _('Versions') }}
    + {% for slug, url in listed_versions %} +
    {{ slug }}
    + {% endfor %} +
    +
    + {# Translators: The phrase "Read the Docs" is not translated #} +
    {{ _('On Read the Docs') }}
    +
    + {{ _('Project Home') }} +
    +
    + {{ _('Builds') }} +
    +
    + {{ _('Downloads') }} +
    +
    + +
    + + Hosted by Read the Docs + · + Privacy Policy + + + {##} +
    +
    diff --git a/about/docs_changelog.rst b/about/docs_changelog.rst index 5f9ea448b..9edceffdb 100644 --- a/about/docs_changelog.rst +++ b/about/docs_changelog.rst @@ -5,7 +5,7 @@ Documentation changelog The documentation is continually being improved. The release of version 3.2 includes many new tutorials, many fixes and updates for old tutorials, and many updates -to the :ref:`class reference `. Below is a list of new tutorials +to the :ref:`class reference `. Below is a list of new tutorials added since version 3.1. .. note:: This document only contains new tutorials so not all changes are reflected, diff --git a/about/index.rst b/about/index.rst deleted file mode 100644 index 5a3f59959..000000000 --- a/about/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -About -===== - -.. toctree:: - :maxdepth: 1 - :name: toc-about - - introduction - faq - troubleshooting - list_of_features - docs_changelog - release_policy - complying_with_licenses - -.. history -.. authors -.. license diff --git a/classes/index.rst b/classes/index.rst index 185946541..b0358f15b 100644 --- a/classes/index.rst +++ b/classes/index.rst @@ -1,5 +1,7 @@ :github_url: hide +.. _doc_class_reference: + Godot API ========= diff --git a/community/contributing/contributing_to_the_documentation.rst b/community/contributing/contributing_to_the_documentation.rst index 9158d698e..e5101a1c4 100644 --- a/community/contributing/contributing_to_the_documentation.rst +++ b/community/contributing/contributing_to_the_documentation.rst @@ -26,7 +26,7 @@ request triggers a rebuild of the online documentation upon merging. .. warning:: The class reference's source files are in the `Godot engine repository `_. We generate - the :ref:`Godot API ` section of this documentation + the :ref:`Godot API ` section of this documentation from them. If you want to update the description of a class, its methods, or properties, read :ref:`doc_updating_the_class_reference`. diff --git a/community/contributing/documentation_guidelines.rst b/community/contributing/documentation_guidelines.rst index 9320710e3..d5ceffb75 100644 --- a/community/contributing/documentation_guidelines.rst +++ b/community/contributing/documentation_guidelines.rst @@ -27,8 +27,8 @@ documentation. .. warning:: The class reference's source files are in the `Godot engine repository `_. We generate the :ref:`Godot API - ` section of this documentation from them. If you want to update the - description of a class, its methods, or properties, read + ` section of this documentation from them. If you want + to update the description of a class, its methods, or properties, read :ref:`doc_updating_the_class_reference`. .. warning:: If you want to edit the **API reference**, please note that it diff --git a/community/contributing/updating_the_class_reference.rst b/community/contributing/updating_the_class_reference.rst index 891e1633b..cbbdf89c5 100644 --- a/community/contributing/updating_the_class_reference.rst +++ b/community/contributing/updating_the_class_reference.rst @@ -5,7 +5,7 @@ Contributing to the class reference .. highlight:: shell -The class reference is available online in the :ref:`classes ` +The class reference is available online in the :ref:`classes ` section of the documentation and in the Godot editor, from the help menu. In the class reference, some methods, variables, and signals lack descriptions. @@ -45,7 +45,7 @@ repository: `doc/classes/ .. warning:: Always edit the API reference through these source XML files. Do not edit the generated ``.rst`` files :ref:`in the online documentation - `, hosted in the `godot-docs + `, hosted in the `godot-docs `_ repository. .. warning:: diff --git a/community/contributing/ways_to_contribute.rst b/community/contributing/ways_to_contribute.rst index ea22647dc..0c3e32011 100644 --- a/community/contributing/ways_to_contribute.rst +++ b/community/contributing/ways_to_contribute.rst @@ -197,7 +197,7 @@ There are two separate resources referred to as "documentation" in Godot: - **The class reference.** This is the documentation for the complete Godot API as exposed to GDScript and the other scripting languages. It can be consulted offline, directly in Godot's code editor, or online at :ref:`Godot API - `. To contribute to the class reference, you have to edit the + `. To contribute to the class reference, you have to edit the XML file corresponding to the class and make a pull request. See :ref:`doc_updating_the_class_reference` and :ref:`doc_class_reference_writing_guidelines` for more details. diff --git a/conf.py b/conf.py index 07cbf7d4b..a4bd24fef 100644 --- a/conf.py +++ b/conf.py @@ -2,6 +2,7 @@ # # Godot Engine documentation build configuration file +import sphinx import sphinx_rtd_theme import sys import os @@ -76,7 +77,7 @@ master_doc = "index" # General information about the project project = "Godot Engine" copyright = ( - "2014-present Juan Linietsky, Ariel Manzur and the Godot community (CC-BY 3.0)" + "2014-present Juan Linietsky, Ariel Manzur and the Godot community (CC BY 3.0)" ) author = "Juan Linietsky, Ariel Manzur and the Godot community" @@ -96,20 +97,20 @@ if env_tags is not None: # Language / i18n supported_languages = { - "en": "Godot Engine (%s) documentation in English", - "de": "Godot Engine (%s) Dokumentation auf Deutsch", - "es": "Documentación de Godot Engine (%s) en español", - "fr": "Documentation de Godot Engine (%s) en français", - "fi": "Godot Engine (%s) dokumentaatio suomeksi", - "it": "Godot Engine (%s) documentazione in italiano", - "ja": "Godot Engine (%s)の日本語のドキュメント", - "ko": "Godot Engine (%s) 문서 (한국어)", - "pl": "Dokumentacja Godot Engine (%s) w języku polskim", - "pt_BR": "Documentação da Godot Engine (%s) em Português Brasileiro", - "ru": "Документация Godot Engine (%s) на русском языке", - "uk": "Документація до Godot Engine (%s) українською мовою", - "zh_CN": "Godot Engine (%s) 简体中文文档", - "zh_TW": "Godot Engine (%s) 正體中文 (台灣) 文件", + "en": "Godot Engine %s documentation in English", + "de": "Godot Engine %s Dokumentation auf Deutsch", + "es": "Documentación de Godot Engine %s en español", + "fr": "Documentation de Godot Engine %s en français", + "fi": "Godot Engine %s dokumentaatio suomeksi", + "it": "Godot Engine %s documentazione in italiano", + "ja": "Godot Engine %sの日本語のドキュメント", + "ko": "Godot Engine %s 문서 (한국어)", + "pl": "Dokumentacja Godot Engine %s w języku polskim", + "pt_BR": "Documentação da Godot Engine %s em Português Brasileiro", + "ru": "Документация Godot Engine %s на русском языке", + "uk": "Документація до Godot Engine %s українською мовою", + "zh_CN": "Godot Engine %s 简体中文文档", + "zh_TW": "Godot Engine %s 正體中文 (台灣) 文件", } language = os.getenv("READTHEDOCS_LANGUAGE", "en") @@ -154,9 +155,11 @@ html_theme_options = { "logo_only": True, # Collapse navigation (False makes it tree-like) "collapse_navigation": False, + # Hide the documentation version name/number under the logo + "display_version": False, } -html_title = supported_languages[language] % version +html_title = supported_languages[language] % ( "(" + version + ")" ) # VCS options: https://docs.readthedocs.io/en/latest/vcs.html#github html_context = { @@ -167,6 +170,7 @@ html_context = { "conf_py_path": "/", # Path in the checkout to the docs root "godot_inject_language_links": True, "godot_docs_supported_languages": list(supported_languages.keys()), + "godot_docs_title": supported_languages[language], "godot_docs_basepath": "https://docs.godotengine.org/", "godot_docs_suffix": ".html", "godot_default_lang": "en", @@ -174,9 +178,15 @@ html_context = { # Distinguish local development website from production website. # This prevents people from looking for changes on the production website after making local changes :) "godot_title_prefix": "" if on_rtd else "(DEV) ", + # Set this to `True` when in the `latest` branch to clearly indicate to the reader + # that they are not reading the `stable` documentation. + "godot_is_latest": False, + "godot_version": "3.5", + # Enables a banner that displays the up-to-date status of each article. + "godot_show_article_status": False, } -html_logo = "img/docs_logo.png" +html_logo = "img/docs_logo.svg" # These folders are copied to the documentation's HTML output html_static_path = ["_static"] @@ -186,11 +196,14 @@ html_extra_path = ["robots.txt"] # These paths are either relative to html_static_path # or fully qualified paths (e.g. https://...) html_css_files = [ - "css/custom.css", + "css/custom.css?1", # Increment the number at the end when the file changes to bust the cache. ] +if not on_rtd: + html_css_files.append("css/dev.css") + html_js_files = [ - "js/custom.js", + "js/custom.js?1", # Increment the number at the end when the file changes to bust the cache. ] # Output file base name for HTML help builder @@ -242,11 +255,11 @@ gettext_compact = False # https://github.com/sphinx-doc/sphinx/issues/7768 to see what would be relevant for us. figure_language_filename = "{root}.{language}{ext}" -import sphinx cwd = os.getcwd() sphinx_original_get_image_filename_for_language = sphinx.util.i18n.get_image_filename_for_language + def godot_get_image_filename_for_language(filename, env): """ Hack the absolute path returned by Sphinx based on `figure_language_filename` diff --git a/getting_started/introduction/learning_new_features.rst b/getting_started/introduction/learning_new_features.rst index c3689261d..bac0ea39e 100644 --- a/getting_started/introduction/learning_new_features.rst +++ b/getting_started/introduction/learning_new_features.rst @@ -33,7 +33,7 @@ from within the Godot editor. To do so, go to Help -> Search or press .. image:: img/manual_class_reference_search.png -To browse it online, head to the manual's :ref:`Class Reference ` +To browse it online, head to the manual's :ref:`Class Reference ` section. A class reference's page tells you: diff --git a/img/docs_logo.png b/img/docs_logo.png deleted file mode 100644 index c13b06885..000000000 Binary files a/img/docs_logo.png and /dev/null differ diff --git a/img/docs_logo.svg b/img/docs_logo.svg new file mode 100644 index 000000000..fe52d3e69 --- /dev/null +++ b/img/docs_logo.svg @@ -0,0 +1 @@ + diff --git a/index.rst b/index.rst index 91df1626e..ec931fed1 100644 --- a/index.rst +++ b/index.rst @@ -10,7 +10,7 @@ Godot Docs – *3.5* branch .. only:: i18n .. note:: This documentation is translated from the `original English one - `_ by community members + `_ by community members on `Weblate `_. Depending on the translation effort's completion level, you may @@ -19,8 +19,9 @@ Godot Docs – *3.5* branch ones on Weblate. For the time being, localized translations are only available for - the "latest" (development) branch, but should be suitable to learn - how to use stable Godot releases nevertheless. + the "stable" branch. You can still view the English documentation for + other engine versions using the "Read the Docs" panel at the bottom + of the sidebar. Welcome to the official documentation of `Godot Engine `__, the free and open source community-driven 2D and 3D game engine! If you are new @@ -28,42 +29,62 @@ to this documentation, we recommend that you read the :ref:`introduction page ` to get an overview of what this documentation has to offer. -The table of contents below and in the sidebar should let you easily access the -documentation for your topic of interest. You can also use the search function -in the top left corner. +The table of contents in the sidebar should let you easily access the documentation +for your topic of interest. You can also use the search function in the top-left corner. -You can also `download an HTML copy `__ -for offline reading (updated every Monday). Extract the ZIP archive then open -the top-level ``index.html`` in a web browser. +Get involved +------------ -.. note:: Godot Engine is an open source project developed by a community of - volunteers. The documentation team can always use your - feedback and help to improve the tutorials and class reference. If - you don't understand something, or cannot find what you - are looking for in the docs, help us make the documentation better - by letting us know! +Godot Engine is an open source project developed by a community of volunteers. +The documentation team can always use your feedback and help to improve the +tutorials and class reference. If you don't understand something, or cannot find +what you are looking for in the docs, help us make the documentation better +by letting us know! - Submit an issue or pull request on the `GitHub repository - `_, - help us `translate the documentation - `_ into your - language, or talk to us on the - ``#documentation`` channel on the `Godot Contributors Chat - `_! +Submit an issue or pull request on the `GitHub repository `_, +help us `translate the documentation `_ +into your language, or talk to us on the ``#documentation`` channel on the +`Godot Contributors Chat `_! .. centered:: |weblate_widget| -The main documentation for the site is organized into the following sections: +Offline documentation +--------------------- + +To browse the documentation offline, you can use the mirror of the documentation +hosted on `DevDocs `__. To enable offline browsing on +DevDocs, you need to: + +- Click the three dots in the top-left corner, choose **Preferences**. +- Enable the desired version of the Godot documentation by checking the box + next to it in the sidebar. +- Click the three dots in the top-left corner, choose **Offline data**. +- Click the **Install** link next to the Godot documentation. + +You can also `download an HTML copy `__ +for offline reading (updated every Monday). Extract the ZIP archive then open +the top-level ``index.html`` in a web browser. + + +.. Below is the main table-of-content tree of the documentation website. + It is hidden on the page itself, but it makes up the sidebar for navigation. .. toctree:: + :hidden: :maxdepth: 1 - :caption: General + :caption: About :name: sec-general - about/index - + about/introduction + about/faq + about/troubleshooting + about/list_of_features + about/docs_changelog + about/release_policy + about/complying_with_licenses .. toctree:: + :hidden: :maxdepth: 1 :caption: Getting started :name: sec-learn @@ -74,19 +95,23 @@ The main documentation for the site is organized into the following sections: getting_started/first_3d_game/index -.. The sections below are sorted alphabetically. Please keep them that way. +.. Sections below are split into two groups. First come meta sections, covering + general matters. Below that different areas of the engine are listed. + These sections are sorted alphabetically. Please keep them that way. .. toctree:: + :hidden: :maxdepth: 1 - :caption: Tutorials + :caption: Manual :name: sec-tutorials + tutorials/best_practices/index + tutorials/editor/index + tutorials/2d/index tutorials/3d/index tutorials/animation/index tutorials/assets_pipeline/index tutorials/audio/index - tutorials/best_practices/index - tutorials/editor/index tutorials/export/index tutorials/i18n/index tutorials/inputs/index @@ -106,6 +131,7 @@ The main documentation for the site is organized into the following sections: .. toctree:: + :hidden: :maxdepth: 1 :caption: Development :name: sec-devel @@ -117,6 +143,7 @@ The main documentation for the site is organized into the following sections: .. toctree:: + :hidden: :maxdepth: 1 :caption: Community :name: sec-community @@ -128,16 +155,9 @@ The main documentation for the site is organized into the following sections: .. toctree:: + :hidden: :maxdepth: 1 :caption: Class reference :name: sec-class-ref classes/index - - -.. Indices and tables -.. ------------------ -.. -.. * :ref:`genindex` -.. * :ref:`modindex` -.. * :ref:`search`