Skip to content

Commit 9cc49df

Browse files
authored
Some docs on stylesheets and update linting fix to KO hidden pattern (#585)
This adds some more documentation sourced from our theme styles, including the pattern we've been using to replace the Knockout ``visible`` binding with a pattern that doesn't need inline styles. https://read-the-docs-docs-landing--585.com.readthedocs.build/projects/ext-theme/en/585/api/stylesheets.html
1 parent 512c439 commit 9cc49df

File tree

11 files changed

+140
-38
lines changed

11 files changed

+140
-38
lines changed

docs/api/stylesheets.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Stylesheets
2+
===========
3+
4+
This repository uses our base FUI/SUI theme, which is shared with our website.
5+
6+
https://github.com/readthedocs/sui-common-theme/
7+
8+
In this repository, there are some additional styles and elements that are
9+
specific to our application or that don't need to be defined at our common
10+
theme. Many of the styles are small bug fixes that don't require additional
11+
documentation, but there are some styles and new elements that are only found
12+
and used in this repository.
13+
14+
Utilities
15+
---------
16+
17+
.. autoanysrc:: hidden
18+
:src: ../src/sui/themes/rtd-application/globals/site.overrides
19+
:analyzer: css
20+
21+
Images
22+
------
23+
24+
.. autoanysrc:: images
25+
:src: ../src/sui/themes/rtd-application/elements/image.overrides
26+
:analyzer: css
27+
28+
Tables
29+
------
30+
31+
.. autoanysrc:: tables
32+
:src: ../src/sui/themes/rtd-application/collections/table.overrides
33+
:analyzer: css

docs/conf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
import docext # noqa
77

88
project = "readthedocsext-theme"
9-
copyright = "2022, Read the Docs, Inc"
9+
copyright = "2025, Read the Docs, Inc"
1010
author = "Read the Docs, Inc"
1111

1212
release = "1.0rc1"
1313
version = release
1414

1515
extensions = [
1616
"docext",
17+
"sphinx.ext.autodoc",
1718
"sphinxcontrib.autoanysrc",
1819
"sphinx_js",
1920
]
@@ -25,6 +26,7 @@
2526

2627
autoanysrc_analyzers = {
2728
"html": "docext.DjangoTemplateAnalyzer",
29+
"css": "docext.CSSAnalyzer",
2830
}
2931

3032
js_source_path = "../src/js"

docs/docext.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
readthedocsext-theme doc extensions
33
"""
44

5+
import re
56
import os
67
import subprocess
78
from pathlib import Path
@@ -12,14 +13,7 @@
1213
logger = logging.getLogger(__name__)
1314

1415

15-
class DjangoTemplateAnalyzer(analyzers.BaseCommentAnalyzer):
16-
17-
"""There are a few errors with this docstring
18-
but black will not reformat any of this"""
19-
20-
comment_starts_with = '{% comment "rst" %}'
21-
comment_ends_with = "{% endcomment %}"
22-
16+
class CommonAnalyzer(analyzers.BaseCommentAnalyzer):
2317
def process(self, content):
2418
first_indent = None
2519

@@ -40,7 +34,26 @@ def process(self, content):
4034
f"Try indenting the block inner text once."
4135
)
4236

43-
yield (line[first_indent:], lineno)
37+
line_content = line[first_indent:]
38+
39+
# Conditionally left strip comment lines out
40+
if hasattr(self, "strip_comment"):
41+
line_content = self.strip_comment(line_content)
42+
43+
yield (line_content, lineno)
44+
45+
46+
class DjangoTemplateAnalyzer(CommonAnalyzer):
47+
comment_starts_with = '{% comment "rst" %}'
48+
comment_ends_with = "{% endcomment %}"
49+
50+
51+
class CSSAnalyzer(CommonAnalyzer):
52+
comment_starts_with = "/*"
53+
comment_ends_with = "*/"
54+
55+
def strip_comment(self, line):
56+
return re.sub(r"^\s?\*\s?", "", line)
4457

4558

4659
def build_init(app):

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Read the Docs -- Application theme
1818

1919
api/templates
2020
api/javascript
21+
api/stylesheets
2122

2223
.. include:: ../README.rst
2324
:start-line: 3

readthedocsext/theme/templates/includes/header.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
<div class="five wide mobile only right aligned column">
5151
<div class="ui wide dropdown"
5252
data-bind="semanticui: {dropdown: {action: 'select'}}">
53-
{# Ignore "avoid inline styles" rule #}
53+
{# Ignore "avoid inline styles" rule. Don't use this hack, this should eventually be a CSS rule instead. #}
5454
{# djlint:off H021 #}
5555
<i class="fad fa-bars large icon" style="--fa-secondary-opacity: 0.8;"></i>
5656
{# djlint:on #}

readthedocsext/theme/templates/projects/partials/project_create_automatic.html

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@
2424
{% endblock project_add_configuration %}
2525

2626
{% block project_add_automatic_search %}
27-
{# Ignore "avoid inline styles" rule #}
28-
{# djlint:off H021 #}
29-
<div class="ui small error message"
30-
data-bind="visible: error"
31-
style="display: none">
32-
{# djlint:on #}
27+
<div class="ui small error message ko hidden"
28+
data-bind="css: {hidden: !error()}">
3329
{% trans "There was an error while syncing your remote repositories" %}
3430
</div>
3531

@@ -127,12 +123,8 @@
127123
connected and why the repository can/cannot be used.
128124

129125
{% endcomment %}
130-
{# Ignore "avoid inline styles" rule #}
131-
{# djlint:off H021 #}
132-
<div class="ui fluid card"
133-
data-bind="visible: is_selected, with: selected"
134-
style="display: none">
135-
{# djlint:on #}
126+
<div class="ui fluid card ko hidden"
127+
data-bind="css: {hidden: !is_selected()}, with: selected">
136128
<div class="content">
137129
<img class="ui right floated mini rounded image"
138130
data-bind="attr: { src: avatar_url }"

setup.cfg

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ install_requires =
2929

3030
[options.extras_require]
3131
docs =
32-
# We can't upgrade Sphinx because of sphinx-js (Sphinx<6)
33-
Sphinx<6
34-
sphinx_rtd_theme<3
35-
sphinxcontrib-autoanysrc<1
36-
sphinx-js
32+
Sphinx>6
33+
sphinx_rtd_theme
34+
sphinxcontrib-autoanysrc>=0.2.0
35+
sphinx-js>=4

src/sui/themes/rtd-application/collections/table.overrides

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
1-
// Build detail page command output table
1+
/*
2+
* Command table variant
3+
* =====================
4+
*
5+
* This is a special table, used solely on the build detail page to list
6+
* commands and steps executed. There is some unique CSS rules here to support
7+
* command highlighting and ANSI sequences.
8+
*
9+
* .. code:: html
10+
*
11+
* <div class="ui command table">
12+
* ...
13+
* </div>
14+
*/
215
.ui.ui.ui.command.table {
16+
/*
17+
* Each command is made of up two rows:
18+
*
19+
* - The first row has two columns, a dropdown expander icon and the
20+
* command executed.
21+
* - The second row is normally hidden until collapsed open, it contains
22+
* two columns: the line number and line contents for each line of output in
23+
* STDOUT.
24+
*/
325
tr {
426
border-bottom: 0px;
527
cursor: unset;
@@ -29,6 +51,16 @@
2951
word-wrap: anywhere;
3052
}
3153

54+
/*
55+
* The STDOUT styling supports ANSI color codes through special classes
56+
that should be added by the backend exectuion through Docker:
57+
*
58+
* .. code:: html
59+
*
60+
* <span class="ansi-black-fg">...</span>
61+
*
62+
* .. note:: ANSI sequences are not yet supported by the build backend.
63+
*/
3264
&.stdout > code {
3365
// ansi_up control character classes
3466
span.ansi-black-fg {

src/sui/themes/rtd-application/elements/image.overrides

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
/*
2+
* Avatar overlapping variant
3+
* ==========================
4+
*
5+
* Used to create stacking avatar bubbles for maintainer and team member lists.
6+
*
7+
* .. code:: html
8+
*
9+
* <div class="ui overlapping avatar images">
10+
* <img class="ui image" src="..." />
11+
* </div>
12+
*/
113
.ui.overlapping.avatar.images {
214
margin-left: 0.25rem;
315
> .ui.image,

src/sui/themes/rtd-application/globals/site.overrides

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,32 @@
44
// chaining more selectors. This rule will override most 3 and 4 selector rules
55
// due to the artificially increased specificity in this rule.
66
.ko.ko.ko.ko.ko {
7-
// There is the Knockout ``visible`` data binding, but this injects a hard
8-
// coded style="display: none;" when the binding is false. This makes default
9-
// styling on initial load hard with CSS and tends to flash the element to the
10-
// user, before the JS loads.
11-
//
12-
// Instead, something like this is preferable:
13-
//
14-
// <div class="ko hidden" data-bind="css: { hidden: !is_showing() }"></div>
7+
/*
8+
* Knockout ``visible`` binding
9+
* ============================
10+
*
11+
* In standard Knockout there is a ``visible`` data binding, but this
12+
* injects a hard coded ``style="display: none;"`` when the binding is false.
13+
* This makes default styling on initial load hard with CSS and tends to
14+
* flash the element to the user, before the JS loads.
15+
*
16+
* In standard Knockout, this would look like:
17+
*
18+
* .. code:: html
19+
*
20+
* <div data-bind="visible: is_showing" style="display: none;"></div>
21+
*
22+
* Using this ``.ko.hidden`` class and the ``css`` binding, this example would instead be:
23+
*
24+
* .. code:: html
25+
*
26+
* <div class="ko hidden" data-bind="css: { hidden: !is_showing() }"></div>
27+
*
28+
* .. note::
29+
* When used as an observable name, executing the observable as a function
30+
* is not required. In the second example, due to nesting and value negation, we
31+
* have to call the observable as a function, ``is_showing()``.
32+
*/
1533
&.hidden {
1634
display: none;
1735
}

0 commit comments

Comments
 (0)