Skip to content

Commit

Permalink
Add integration for questions & answers in relevant pages
Browse files Browse the repository at this point in the history
- Alpine.js is used on the frontend.
- The backend is a static REST API generated by
  <https://github.com/Calinou/godot-qa-api-generator>.
  • Loading branch information
Calinou committed Jan 26, 2021
1 parent bdeb076 commit 9429513
Show file tree
Hide file tree
Showing 44 changed files with 288 additions and 4 deletions.
115 changes: 115 additions & 0 deletions _extensions/godot_questions_answers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
"""
godot_questions_answers
~~~~~~~~~~~~~~~~~~~~~~~
Sphinx extension that adds a ``.. questions-answers:: tag1 tag2 ...`` directive.
This displays a link to view and ask questions on the Godot Questions & Answers platform.
This role should be added at the bottom of relevant pages.
:copyright: Copyright 2020 by The Godot Engine Community
:license: MIT
"""

from docutils import nodes
from docutils.parsers.rst import Directive, directives

# See <https://github.com/coldfix/sphinx-code-tabs/blob/main/sphinx_code_tabs/__init__.py>
# for setup code inspiration.

# The URL to the questions & answers website.
GODOT_QA_URL = "https://godotengine.org/qa"


class QuestionsAnswersNode(nodes.General, nodes.Element):
def __init__(self, tags):
"""
:param str tags: Tags to search for in the Q&A (separated by spaces).
"""
super(QuestionsAnswersNode, self).__init__()
self.tags = tags[0]

@staticmethod
def visit(spht, node):
"""Append opening tags to document body list."""
spht.body.append(
spht.starttag(node, "div", "", **{"class": "questions-answers"})
)

spht.body.append(f"""
<h2>
Top user questions for “{node.tags}
<a href="https://godotengine.org/qa/search?q={node.tags}" target="_blank" rel="noopener" style="font-size: 75%">
(from Godot Q&amp;A)
</a>
</h2>
""")

# See `_static/js/godot-questions-answers.js` for the logic.
spht.body.append(f"""
<section x-data="questionsAnswers()" x-init="loadQuestions('{node.tags}')">
<template x-if="questionsLoaded">
<template x-for="question in questions">
<a :href="question.url">
<article class="questions-answers-question">
<div class="questions-answers-question-score">
<div x-text="question.score" style="font-weight: 700; font-size: 125%"></div>
votes
</div>
<div class="questions-answers-question-answers" :style="`opacity: ${{question.answers === 0 ? '50%' : '100%'}}`">
<div x-text="question.answers" style="font-weight: 700; font-size: 125%"></div>
answers
</div>
<div class="questions-answers-question-title" x-text="question.title"></div>
</article>
</a>
</template>
</template>
<template x-if="!questionsLoaded">
<p style="text-align: center; height: 40rem; padding-top: 1.5rem; margin-top: 3rem">
Loading questions…
</p>
</template>
</section>
""")

spht.body.append(
spht.starttag(
node,
"a",
"Ask a question about “<strong>%s</strong>”" % node.tags,
href="%s/ask?tags=%s" % (GODOT_QA_URL, node.tags),
target="_blank",
rel="noopener",
title="Ask a question on the Godot Q&A platform (opens in a new tab)",
**{"class": "questions-answers-btn"},
)
)
spht.body.append("</a>")

@staticmethod
def depart(spht, node):
"""Append closing tags to document body list."""
spht.body.append("</div>")
# Separate the User questions box from th Previous and Next page buttons.
spht.body.append("<hr>")


class QuestionsAnswers(Directive):
has_content = True

def run(self):
self.assert_has_content()
return [QuestionsAnswersNode(self.content)]


def setup(app):
app.add_js_file("js/alpine.min.js")
app.add_js_file("js/godot-questions-answers.js")
app.add_directive("questions-answers", QuestionsAnswers)
app.add_node(
QuestionsAnswersNode,
html=(QuestionsAnswersNode.visit, QuestionsAnswersNode.depart),
)

return {
"parallel_read_safe": True,
"parallel_write_safe": True,
}
60 changes: 60 additions & 0 deletions _static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@
--btn-neutral-background-color: #f3f6f6;
--btn-neutral-hover-background-color: #e5ebeb;
--footer-color: #808080;

/* Match the filtered background color of the Q&A iframe. */
--qa-box-background-color: #fff;
}

/* Dark theme colors */
Expand Down Expand Up @@ -176,6 +179,14 @@
--btn-neutral-background-color: #404040;
--btn-neutral-hover-background-color: #505050;
--footer-color: #aaa;

/* Match the filtered background color of the Q&A iframe. */
--qa-box-background-color: #131313;
}

/* Crude dark theme for the Q&A integration until we have a proper dark theme for it. */
.questions-answers-iframe {
filter: invert(0.925) hue-rotate(180deg);
}
}

Expand Down Expand Up @@ -1029,3 +1040,52 @@ kbd, .kbd {
.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:active {
background-color: var(--navbar-scrollbar-active-color);
}

.questions-answers {
padding: 1rem;
margin-top: 2rem;
background-color: var(--qa-box-background-color);
box-shadow: 0 0.125rem 0.25rem hsla(0, 0%, 0%, 0.2);
}

a.questions-answers-btn {
display: inline-block;
padding: 0.5rem 1rem;
margin: 0.5rem 0;
color: hsl(0, 0%, 100%);
border-radius: 0.25rem;
background-color: hsl(205, 75%, 35%);
}

a.questions-answers-btn:hover {
background-color: hsl(205, 70%, 40%);
text-decoration: none;
}

a.questions-answers-btn:active {
background-color: hsl(205, 80%, 30%);
}

.questions-answers-question {
--score-answers-width: 2.75rem;
--padding-x: 0.4rem;
display: flex;
flex-direction: row;
align-items: center;
padding: 0.75rem var(--padding-x);
margin: 0.75rem 0;
background-color: hsla(0, 0%, 50%, 0.15);
}

.questions-answers-question-score,
.questions-answers-question-answers {
width: var(--score-answers-width);
font-size: 75%;
text-align: center;
}

.questions-answers-question-title {
--margin-left: 1rem;
margin-left: var(--margin-left);
width: calc(100% - 2 * var(--score-answers-width) - 2 * var(--padding-x) - var(--margin-left));
}
8 changes: 8 additions & 0 deletions _static/js/alpine.min.js

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions _static/js/godot-questions-answers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Don't end the URL below with a trailing slash.
const QA_API_URL = "http://devd.io:8001";

/**
* Returns an object for use by Alpine.js.
* See `godot_questions_answers.py`.
*/
function questionsAnswers() {
return {
questions: [],
questionsLoaded: false,

loadQuestions(tag) {
$.getJSON(`${QA_API_URL}/${tag}.json`, {}).then((response) => {
this.questions = response.data.questions;
this.questionsLoaded = true;
});
}
};
}
3 changes: 3 additions & 0 deletions conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
if not os.getenv("SPHINX_NO_DESCRIPTIONS"):
extensions.append("godot_descriptions")

if not os.getenv("SPHINX_NO_QUESTIONS_ANSWERS"):
extensions.append("godot_questions_answers")

templates_path = ["_templates"]

# You can specify multiple suffix as a list of string: ['.rst', '.md']
Expand Down
2 changes: 2 additions & 0 deletions tutorials/animation/2d_skeletons.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,5 @@ painting! Go to the *Bones* section again to assign them to the right bones.
Once you are all set, you will get much better results:

.. image:: img/skel2d25.gif

.. questions-answers:: 2d skeleton
2 changes: 2 additions & 0 deletions tutorials/animation/animation_track_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,5 @@ a key and have it set to `[STOP]` in the inspector.
scene, you need to enable "Editable Children" in the scene tree to
access its animation player. Also, an animation player cannot
reference itself.

.. questions-answers:: animation track
2 changes: 2 additions & 0 deletions tutorials/animation/animation_tree.rst
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,5 @@ Once retrieved, it can be used by calling one of the many functions it offers:
.. code-tab:: csharp

stateMachine.Travel("SomeState")

.. questions-answers:: animationtree
6 changes: 4 additions & 2 deletions tutorials/animation/cutout_animation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,14 @@ position of hands, feet and other extremities of rigs like the one we've made.
Imagine you want to pose a character's foot in a specific position on the ground.
Without IK chains, each motion of the foot would require rotating and positioning
several other bones (the shin and the thigh at least). This would be quite
complex and lead to imprecise results. IK allows us to move the foot directly
complex and lead to imprecise results. IK allows us to move the foot directly
while the shin and thigh self-adjust.

.. note::

**IK chains in Godot currently work in the editor only**, not
at runtime. They are intended to ease the process of setting keyframes, and are
not currently useful for techniques like procedural animation.
not currently useful for techniques like procedural animation.

To create an IK chain, select a chain of bones from endpoint to
the base for the chain. For example, to create an IK chain for the right
Expand Down Expand Up @@ -374,3 +374,5 @@ Skeletal deform can be used to augment a cutout rig, allowing single pieces to
deform organically (e.g. antennae that wobble as an insect character walks).

This process is described in a :ref:`separate tutorial <doc_2d_skeletons>`.

.. questions-answers:: animation cutout
2 changes: 2 additions & 0 deletions tutorials/animation/introduction.rst
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,5 @@ You usually tweak your animations this way, when the movement doesn't

.. |Play from beginning| image:: img/animation_play_from_beginning.png
.. |Add Animation| image:: img/animation_add.png

.. questions-answers:: animation
2 changes: 2 additions & 0 deletions tutorials/audio/audio_buses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,5 @@ Default bus layout
The default bus layout is automatically saved to the
``res://default_bus_layout.tres`` file. Custom bus arrangements can be saved
and loaded from disk.

.. questions-answers:: audio
4 changes: 3 additions & 1 deletion tutorials/audio/audio_streams.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ your use case best:
at relatively low bitrates.

Keep in mind that while WAV files may contain looping information in their metadata,
Ogg Vorbis files do not. If looping an Ogg Vorbis file is desired,
Ogg Vorbis files do not. If looping an Ogg Vorbis file is desired,
it must be set up using the import options:

.. image:: img/audio_stream_import.png
Expand Down Expand Up @@ -113,3 +113,5 @@ Enable it by setting it depending on how objects will be moved:
use **Idle** for objects moved using ``_process``, or **Physics**
for objects moved using ``_physics_process``. The tracking will
happen automatically.

.. questions-answers:: audio
2 changes: 2 additions & 0 deletions tutorials/audio/recording_with_microphone.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,5 @@ To playback the recording, you assign the recording as the stream of the

To save the recording, you call ``save_to_wav()`` with the path to a file.
In this demo, the path is defined by the user via a ``LineEdit`` input box.

.. questions-answers:: audio record
2 changes: 2 additions & 0 deletions tutorials/audio/sync_with_audio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,5 @@ Here is the same code as before using this approach:
# Compensate for output latency.
time -= AudioServer.get_output_latency()
print("Time is: ", time)

.. questions-answers:: audio
2 changes: 2 additions & 0 deletions tutorials/editor/command_line_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,5 @@ always have the shebang run Godot straight from where it is located as follows:
::

#!/usr/bin/godot -s

.. questions-answers:: command-line
2 changes: 2 additions & 0 deletions tutorials/editor/external_editor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ We have official plugins for the following code editors:

- `Visual Studio Code <https://github.com/godotengine/godot-vscode-plugin>`_
- `Emacs <https://github.com/godotengine/emacs-gdscript-mode>`_

.. questions-answers:: external-editor
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_android.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,5 @@ and ARMv8 is usually sufficient to cover most devices in use today.
You can optimize the size further by compiling an Android export template with
only the features you need. See :ref:`doc_optimizing_for_size` for more
information.

.. questions-answers:: export android
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_dedicated_servers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ If you have experience with containers, you could also look into wrapping your
dedicated server in a `Docker <https://www.docker.com/>`__ container. This way,
it can be used more easily in an automatic scaling setup (which is outside the
scope of this tutorial).

.. questions-answers:: export server
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_ios.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,5 @@ Services for iOS

Special iOS services can be used in Godot. Check out the
:ref:`doc_services_for_ios` page.

.. questions-answers:: export ios
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_pc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ does not contain the editor and debugger.

If you export for Windows with embedded PCK files, you will not be able to
sign the program, it will break.

.. questions-answers:: export desktop
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_uwp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,5 @@ It's also possible to install by using the ``Add-AppxPackage`` PowerShell cmdlet
.. note:: If you want to update your already installed app, you must
update the version number on the new package or first uninstall
the previous package.

.. questions-answers:: export uwp
2 changes: 2 additions & 0 deletions tutorials/export/exporting_for_web.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,5 @@ defaulting to ``false`` to prevent polluting the global namespace::
# execute in global execution context,
# thus adding a new JavaScript global variable `SomeGlobal`
JavaScript.eval("var SomeGlobal = {};", true)

.. questions-answers:: export html5
2 changes: 2 additions & 0 deletions tutorials/export/exporting_pcks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,5 @@ is. The most important thing is to identify how one plans to distribute future
content for their game and develop a workflow that is customized for that
purpose. Godot should make that process smooth regardless of which route a
developer pursues.

.. questions-answers:: export pck
2 changes: 2 additions & 0 deletions tutorials/export/exporting_projects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,5 @@ depending on your needs.
- Compressed format. Smaller file size, but slower to read/write.
- Readable and writable using tools normally present on the user's operating system.
This can be useful to make modding easier (see also :ref:`doc_exporting_pcks`).

.. questions-answers:: export
2 changes: 2 additions & 0 deletions tutorials/export/feature_tags.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ Customizing the build

Feature tags can be used to customize a build process too, by writing a custom **ExportPlugin**.
They are also used to specify which shared library is loaded and exported in **GDNative**.

.. questions-answers:: feature-tags
2 changes: 2 additions & 0 deletions tutorials/export/one-click_deploy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ Using one-click deploy
- Click the button to export to the desired platform in one click.

.. image:: img/oneclick.png

.. questions-answers:: one-click-deploy
2 changes: 2 additions & 0 deletions tutorials/i18n/internationalizing_games.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,5 @@ For instance, for Spanish, this would be ``application/name_es``:

If you are unsure about the language code to use, refer to the
:ref:`list of locale codes <doc_locales>`.

.. questions-answers:: localization
2 changes: 2 additions & 0 deletions tutorials/i18n/localization_using_gettext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,5 @@ the command below:
If there are syntax errors or warnings, they will be displayed in the console.
Otherwise, ``msgfmt`` won't output anything.

.. questions-answers:: localization
2 changes: 2 additions & 0 deletions tutorials/physics/collision_shapes_2d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,5 @@ If you run into performance issues, you may have to make tradeoffs in terms of
accuracy. Most games out there don't have a 100% accurate collision. They find
creative ways to hide it or otherwise make it unnoticeable during normal
gameplay.

.. questions-answers:: 2d physics collision
Loading

0 comments on commit 9429513

Please sign in to comment.