diff --git a/.github/workflows/antsibull-docs.yml b/.github/workflows/antsibull-docs.yml index 85c538c5..23aaec51 100644 --- a/.github/workflows/antsibull-docs.yml +++ b/.github/workflows/antsibull-docs.yml @@ -37,7 +37,7 @@ jobs: antsibull_docs_parser_ref: - main include: - - options: '--use-current --use-html-blobs --no-breadcrumbs community.crypto community.docker' + - options: '--use-current --use-html-blobs --no-breadcrumbs community.crypto community.docker --extra-conf antsibull_ext_color_scheme=none' python: '3.9' - options: '--use-current --output-format simplified-rst community.crypto community.docker' python: '3.11' diff --git a/changelogs/fragments/254-theme-colors.yml b/changelogs/fragments/254-theme-colors.yml new file mode 100644 index 00000000..c5d594bc --- /dev/null +++ b/changelogs/fragments/254-theme-colors.yml @@ -0,0 +1,2 @@ +minor_changes: + - "The colors used by the CSS provided by the Antsibull Sphinx extension can now be overridden (https://github.com/ansible-community/antsibull-docs/pull/254)." diff --git a/docs/index.md b/docs/index.md index 80b0b293..ea0d65e0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -35,6 +35,15 @@ The `sphinx_antsibull_ext` [Sphinx extension](https://www.sphinx-doc.org/en/mast extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'notfound.extension', 'sphinx_antsibull_ext'] ``` +It is possible to configure the color scheme used by the extension using the `antsibull_ext_color_scheme` configuration. Currently, two values are supported: + +1. `default`: the default colors. +2. `none`: define no colors. You can use this if you want to override all colors by your own definition and thus have no need for the default colors to be included. + +The default color scheme can be found in [src/sphinx_antsibull_ext/css/colors-default.scss](https://github.com/ansible-community/antsibull-docs/blob/main/src/sphinx_antsibull_ext/css/colors-default.scss). See the [MDN page on using CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) for information on how the color definitions work. + +Please note that the color scheme only works for HTML output. The colors for LaTeX / PDF output are hardcoded and currently cannot be modified. + ## License Unless otherwise noted in the code, it is licensed under the terms of the GNU diff --git a/src/sphinx_antsibull_ext/antsibull-minimal.css b/src/sphinx_antsibull_ext/antsibull-minimal.css index fdc8414b..a5497b8b 100644 --- a/src/sphinx_antsibull_ext/antsibull-minimal.css +++ b/src/sphinx_antsibull_ext/antsibull-minimal.css @@ -1,3 +1,4 @@ @charset "UTF-8"; /* Copyright (c) Ansible and contributors */ -/* GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) */.ansible-links{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-content:flex-start}.ansible-links>*{margin:2px 4px!important}.ansible-links>li{list-style:none!important}.ansible-links>li>p{display:inline}.ansible-links a{background-color:#5bbdbf;border-radius:3px;color:#fff;cursor:pointer;display:block;padding:4px 12px}.ansible-links a:active,.ansible-links a:focus,.ansible-links a:hover{background-color:#91d9db}.ansible-links a:focus{outline:3px solid #204748}table.documentation-table{border-bottom:1px solid #000;border-right:1px solid #000}table.documentation-table th{background-color:#6ab0de}table.documentation-table td,table.documentation-table th{border-left:1px solid #000;border-top:1px solid #000;padding:4px}table.documentation-table td.elbow-placeholder{border-top:0;min-width:30px;width:30px}table.documentation-table td{vertical-align:top}table.documentation-table td:first-child{white-space:nowrap}table.documentation-table tr .ansibleOptionLink{display:inline-block}table.documentation-table tr .ansibleOptionLink:after{content:"🔗";opacity:0}table.documentation-table tr:hover .ansibleOptionLink:after{opacity:1}table.documentation-table tr:nth-child(odd){background-color:#fff}table.documentation-table tr:nth-child(2n){background-color:#e7f2fa}table.ansible-option-table{border-color:#000!important;display:table;height:1px}table.ansible-option-table tr{height:100%}table.ansible-option-table td,table.ansible-option-table th{border-color:#000!important;border-bottom:none!important;vertical-align:top!important}table.ansible-option-table th>p{font-size:medium!important}table.ansible-option-table thead tr{background-color:#6ab0de}table.ansible-option-table tbody .row-odd td{background-color:#fff!important}table.ansible-option-table tbody .row-even td{background-color:#e7f2fa!important}table.ansible-option-table ul>li>p{margin:0!important}table.ansible-option-table ul>li>div[class^=highlight]{margin-bottom:4px!important}table.ansible-option-table p.ansible-option-title{display:inline}table.ansible-option-table .ansible-option-type-line{font-size:small;margin-bottom:0}table.ansible-option-table .ansible-option-elements,table.ansible-option-table .ansible-option-type{color:purple}table.ansible-option-table .ansible-option-required{color:red}table.ansible-option-table .ansible-option-versionadded{color:#006400;font-size:small}table.ansible-option-table .ansible-option-aliases{color:#006400;white-space:normal}table.ansible-option-table .ansible-option-line{margin-top:8px}table.ansible-option-table .ansible-option-choices-default-mark,table.ansible-option-table .ansible-option-default,table.ansible-option-table .ansible-option-default-bold{color:blue}table.ansible-option-table .ansible-option-sample{color:blue;word-wrap:break-word;word-break:break-all}table.ansible-option-table .ansible-option-sample-bold{color:#000}table.ansible-option-table .ansible-attribute-support-none{color:red}table.ansible-option-table .ansible-attribute-support-partial{color:#a5a500}table.ansible-option-table .ansible-attribute-support-full{color:green}table.ansible-option-table .ansibleOptionLink{display:inline-block}table.ansible-option-table .ansibleOptionLink:after{content:"🔗";opacity:0}table.ansible-option-table p{margin:0 0 8px}table.ansible-option-table tr:hover .ansibleOptionLink:after{opacity:1}table.ansible-option-table td{padding:0!important;white-space:normal}table.ansible-option-table td>div.ansible-option-cell{border-top:1px solid #000;padding:8px 16px}table.ansible-option-table td:first-child{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:inherit;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}table.ansible-option-table td:first-child>div.ansible-option-cell{height:inherit;-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;max-width:100%;white-space:nowrap}table.ansible-option-table .ansible-option-indent{border-right:1px solid #000;margin-left:2em}table.ansible-option-table .ansible-attribute-support-label{display:none}@media (max-width:1200px){table.ansible-option-table{border:none!important;display:block;height:unset}table.ansible-option-table thead{display:none}table.ansible-option-table tbody,table.ansible-option-table td,table.ansible-option-table tr{border:none!important;display:block}table.ansible-option-table tbody .row-even td,table.ansible-option-table tbody .row-odd td{background-color:unset!important}table.ansible-option-table td>div.ansible-option-cell{border-top:none}table.ansible-option-table td:first-child>div.ansible-option-cell{background-color:#e7f2fa!important}table.ansible-option-table td:not(:first-child){display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}table.ansible-option-table td:not(:first-child)>div.ansible-option-cell{margin-left:1em}table.ansible-option-table .ansible-option-indent,table.ansible-option-table .ansible-option-indent-desc{border:none;border-right:3px solid #e7f2fa;margin-left:1em}table.ansible-option-table .ansible-attribute-support-label{display:unset}}.ansible-version-added{font-style:italic}.ansible-option a.reference.external,.ansible-option a.reference.external:hover,.ansible-option a.reference.internal,.ansible-option a.reference.internal:hover,.ansible-option-value a.reference.external,.ansible-option-value a.reference.external:hover,.ansible-option-value a.reference.internal,.ansible-option-value a.reference.internal:hover,.ansible-return-value a.reference.external,.ansible-return-value a.reference.external:hover,.ansible-return-value a.reference.internal,.ansible-return-value a.reference.internal:hover{color:unset} \ No newline at end of file +/* GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) */ +/* INSERT COLOR SCHEME HERE */.ansible-links{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-webkit-justify-content:flex-start;-ms-flex-pack:start;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-content:flex-start}.ansible-links>*{margin:2px 4px!important}.ansible-links>li{list-style:none!important}.ansible-links>li>p{display:inline}.ansible-links a{background-color:var(--antsibull-links-background);border-radius:3px;color:var(--antsibull-links-text);cursor:pointer;display:block;padding:4px 12px}.ansible-links a:active,.ansible-links a:focus,.ansible-links a:hover{background-color:var(--antsibull-links-background-active)}.ansible-links a:focus{outline:3px solid var(--antsibull-links-focus-outline)}table.documentation-table{border-bottom:1px solid var(--antsibull-table-border);border-right:1px solid var(--antsibull-table-border)}table.documentation-table th{background-color:var(--antsibull-table-background-header)}table.documentation-table td,table.documentation-table th{border-left:1px solid var(--antsibull-table-border);border-top:1px solid var(--antsibull-table-border);padding:4px}table.documentation-table td.elbow-placeholder{border-top:0;min-width:30px;width:30px}table.documentation-table td{vertical-align:top}table.documentation-table td:first-child{white-space:nowrap}table.documentation-table tr .ansibleOptionLink{display:inline-block}table.documentation-table tr .ansibleOptionLink:after{content:"🔗";opacity:0}table.documentation-table tr:hover .ansibleOptionLink:after{opacity:1}table.documentation-table tr:nth-child(odd){background-color:var(--antsibull-table-background-odd)}table.documentation-table tr:nth-child(2n){background-color:var(--antsibull-table-background-even)}table.ansible-option-table{border-color:var(--antsibull-table-border)!important;display:table;height:1px}table.ansible-option-table tr{height:100%}table.ansible-option-table td,table.ansible-option-table th{border-color:var(--antsibull-table-border)!important;border-bottom:none!important;vertical-align:top!important}table.ansible-option-table th>p{font-size:medium!important}table.ansible-option-table thead tr{background-color:var(--antsibull-table-background-header)}table.ansible-option-table tbody .row-odd td{background-color:var(--antsibull-table-background-odd)!important}table.ansible-option-table tbody .row-even td{background-color:var(--antsibull-table-background-even)!important}table.ansible-option-table ul>li>p{margin:0!important}table.ansible-option-table ul>li>div[class^=highlight]{margin-bottom:4px!important}table.ansible-option-table p.ansible-option-title{display:inline}table.ansible-option-table .ansible-option-type-line{font-size:small;margin-bottom:0}table.ansible-option-table .ansible-option-type{color:var(--antsibull-option-type)}table.ansible-option-table .ansible-option-elements{color:var(--antsibull-option-elements)}table.ansible-option-table .ansible-option-required{color:var(--antsibull-option-required)}table.ansible-option-table .ansible-option-versionadded{color:var(--antsibull-option-version-added);font-size:small}table.ansible-option-table .ansible-option-aliases{color:var(--antsibull-option-aliases);white-space:normal}table.ansible-option-table .ansible-option-line{margin-top:8px}table.ansible-option-table .ansible-option-choices-default-mark,table.ansible-option-table .ansible-option-default,table.ansible-option-table .ansible-option-default-bold{color:var(--antsibull-option-default)}table.ansible-option-table .ansible-option-sample{color:var(--antsibull-option-sample);word-wrap:break-word;word-break:break-all}table.ansible-option-table .ansible-option-sample-bold{color:var(--antsibull-option-sample-header)}table.ansible-option-table .ansible-attribute-support-none{color:var(--antsibull-attribute-support-none)}table.ansible-option-table .ansible-attribute-support-partial{color:var(--antsibull-attribute-support-partial)}table.ansible-option-table .ansible-attribute-support-full{color:var(--antsibull-attribute-support-full)}table.ansible-option-table .ansible-attribute-support-na{color:var(--antsibull-attribute-support-na)}table.ansible-option-table .ansibleOptionLink{display:inline-block}table.ansible-option-table .ansibleOptionLink:after{content:"🔗";opacity:0}table.ansible-option-table p{margin:0 0 8px}table.ansible-option-table tr:hover .ansibleOptionLink:after{opacity:1}table.ansible-option-table td{padding:0!important;white-space:normal}table.ansible-option-table td>div.ansible-option-cell{border-top:1px solid var(--antsibull-table-border);padding:8px 16px}table.ansible-option-table td:first-child{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;height:inherit;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}table.ansible-option-table td:first-child>div.ansible-option-cell{height:inherit;-webkit-box-flex:1;-webkit-flex:1 0 auto;-ms-flex:1 0 auto;flex:1 0 auto;max-width:100%;white-space:nowrap}table.ansible-option-table .ansible-option-indent{border-right:1px solid var(--antsibull-table-border);margin-left:2em}table.ansible-option-table .ansible-attribute-support-label{display:none}@media (max-width:1200px){table.ansible-option-table{border:none!important;display:block;height:unset}table.ansible-option-table thead{display:none}table.ansible-option-table tbody,table.ansible-option-table td,table.ansible-option-table tr{border:none!important;display:block}table.ansible-option-table tbody .row-even td,table.ansible-option-table tbody .row-odd td{background-color:unset!important}table.ansible-option-table td>div.ansible-option-cell{border-top:none}table.ansible-option-table td:first-child>div.ansible-option-cell{background-color:var(--antsibull-narrowtable-background)!important}table.ansible-option-table td:not(:first-child){display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}table.ansible-option-table td:not(:first-child)>div.ansible-option-cell{margin-left:1em}table.ansible-option-table .ansible-option-indent,table.ansible-option-table .ansible-option-indent-desc{border:none;border-right:3px solid var(--antsibull-narrowtable-background);margin-left:1em}table.ansible-option-table .ansible-attribute-support-label{display:unset}}.ansible-version-added{font-style:italic}.ansible-option a.reference.external,.ansible-option a.reference.external:hover,.ansible-option a.reference.internal,.ansible-option a.reference.internal:hover,.ansible-option-value a.reference.external,.ansible-option-value a.reference.external:hover,.ansible-option-value a.reference.internal,.ansible-option-value a.reference.internal:hover,.ansible-return-value a.reference.external,.ansible-return-value a.reference.external:hover,.ansible-return-value a.reference.internal,.ansible-return-value a.reference.internal:hover{color:unset} \ No newline at end of file diff --git a/src/sphinx_antsibull_ext/assets.py b/src/sphinx_antsibull_ext/assets.py index eba96d93..0e40951c 100644 --- a/src/sphinx_antsibull_ext/assets.py +++ b/src/sphinx_antsibull_ext/assets.py @@ -12,6 +12,7 @@ import os import pkgutil +from sphinx.config import ENUM from sphinx.util.osutil import ensuredir BUILDER_FILES = { @@ -53,6 +54,39 @@ if _builder_name not in BUILDER_FILES and _alias in BUILDER_FILES: BUILDER_FILES[_builder_name] = BUILDER_FILES[_alias] +_AVAILABLE_COLOR_SCHEMES = [ + "none", + "default", +] + + +def get_color_scheme_content(color_scheme: str) -> bytes: + if color_scheme == "none": + return b"" + + filename = f"colors-{color_scheme}.css" + data = pkgutil.get_data("sphinx_antsibull_ext", filename) + if data is not None: + return data + raise RuntimeError( + f"Internal error: cannot find {filename} in sphinx_antsibull_ext package" + ) + + +def substitue_color_scheme(data: bytes, color_scheme: str) -> bytes: + return data.replace( + b"/* INSERT COLOR SCHEME HERE */", get_color_scheme_content(color_scheme) + ) + + +def get_color_scheme(app) -> str: + color_scheme = app.config.antsibull_ext_color_scheme + if color_scheme not in _AVAILABLE_COLOR_SCHEMES: + schemes = ", ".join(_AVAILABLE_COLOR_SCHEMES) + msg = f"Color scheme {color_scheme!r} is not available. Use one of {schemes}." + raise RuntimeError(f"Antsibull Sphinx extension: {msg}") + return color_scheme + def _copy_asset_files(app): """ @@ -64,6 +98,9 @@ def _copy_asset_files(app): raise RuntimeError( f"Internal error: cannot find {file} in sphinx_antsibull_ext package" ) + if file == "antsibull-minimal.css": + data = substitue_color_scheme(data, color_scheme=get_color_scheme(app)) + path = os.path.join(app.outdir, directory) if directory else app.outdir ensuredir(path) destination = os.path.join(path, file) @@ -100,6 +137,14 @@ def setup_assets(app): """ Setup assets for a Sphinx app object. """ + # Add CSS related options + app.add_config_value( + "antsibull_ext_color_scheme", + default="default", + rebuild="", + types=ENUM(*_AVAILABLE_COLOR_SCHEMES), + ) + # Copy assets app.connect("builder-inited", _copy_asset_files_inited) app.connect("build-finished", _copy_asset_files_finished) diff --git a/src/sphinx_antsibull_ext/colors-default.css b/src/sphinx_antsibull_ext/colors-default.css new file mode 100644 index 00000000..3e73c416 --- /dev/null +++ b/src/sphinx_antsibull_ext/colors-default.css @@ -0,0 +1 @@ +:root{--antsibull-links-background:#5bbdbf;--antsibull-links-background-active:#91d9db;--antsibull-links-focus-outline:#204748;--antsibull-links-text:#fff;--antsibull-table-background-header:#6ab0de;--antsibull-table-background-even:#e7f2fa;--antsibull-table-background-odd:#fff;--antsibull-table-border:#000;--antsibull-narrowtable-background:#e7f2fa;--antsibull-option-type:purple;--antsibull-option-elements:purple;--antsibull-option-required:red;--antsibull-option-version-added:#006400;--antsibull-option-aliases:#006400;--antsibull-option-default:blue;--antsibull-option-sample:blue;--antsibull-option-sample-header:#000;--antsibull-attribute-support-none:red;--antsibull-attribute-support-partial:#a5a500;--antsibull-attribute-support-full:green;--antsibull-attribute-support-na:inherit} \ No newline at end of file diff --git a/src/sphinx_antsibull_ext/colors-default.css.license b/src/sphinx_antsibull_ext/colors-default.css.license new file mode 100644 index 00000000..ea1db31c --- /dev/null +++ b/src/sphinx_antsibull_ext/colors-default.css.license @@ -0,0 +1,3 @@ +GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +SPDX-FileCopyrightText: Ansible and contributors +SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/sphinx_antsibull_ext/css/antsibull-minimal.scss b/src/sphinx_antsibull_ext/css/antsibull-minimal.scss index 8da3dd9e..4c067ad0 100644 --- a/src/sphinx_antsibull_ext/css/antsibull-minimal.scss +++ b/src/sphinx_antsibull_ext/css/antsibull-minimal.scss @@ -2,6 +2,8 @@ /* GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) */ // SPDX-License-Identifier: GPL-3.0-or-later +/* INSERT COLOR SCHEME HERE */ + .ansible-links { display: flex; align-items: center; @@ -27,32 +29,32 @@ cursor: pointer; border-radius: 3px; - background-color: #5bbdbf; - color: white; + background-color: var(--antsibull-links-background); + color: var(--antsibull-links-text); &:hover, &:active, &:focus { - background-color: #91d9db; + background-color: var(--antsibull-links-background-active); } &:focus { - outline: 3px solid #204748; + outline: 3px solid var(--antsibull-links-focus-outline); } } } // Documentation table (for module options and return values) table.documentation-table { - border-bottom: 1px solid #000; - border-right: 1px solid #000; + border-bottom: 1px solid var(--antsibull-table-border); + border-right: 1px solid var(--antsibull-table-border); th { - background-color: #6AB0DE; + background-color: var(--antsibull-table-background-header); } td, th { padding: 4px; - border-left: 1px solid #000; - border-top: 1px solid #000; + border-left: 1px solid var(--antsibull-table-border); + border-top: 1px solid var(--antsibull-table-border); } td.elbow-placeholder { @@ -85,10 +87,10 @@ table.documentation-table { } &:nth-child(odd) { - background-color: #FFFFFF; + background-color: var(--antsibull-table-background-odd); } &:nth-child(even) { - background-color: #E7F2FA; + background-color: var(--antsibull-table-background-even); } } } @@ -99,7 +101,7 @@ table.ansible-option-table { // has height 1px, which basically hides it.) display: table; - border-color: #000000 !important; + border-color: var(--antsibull-table-border) !important; // The following is basically ignored, but together with the `height: 100%` for