Skip to content

Commit

Permalink
Add support for lightbox configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasehrlich committed May 4, 2024
1 parent 1ca10cf commit 3b66845
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,25 @@ Add `sphinxcontrib.lightbox2` to the list of `extensions` in your *conf.py*:
``` python
extensions = ["sphinxcontrib.lightbox2"]
```

## Configuration

Lightbox2 offers different configuration [options](https://lokeshdhakar.com/projects/lightbox2/#options).
These options are exposed in `sphinxcontrib-lightbox2` through options in the *conf.py*.

See the mapping of lightbox2 options to Sphinx options

| Lightbox2 option name | Sphinx Option Name | Default Value |
| ----------------------|--------------------|---------------|
| `alwaysShowNavOnTouchDevices` | `lightbox2_always_show_nav_on_touch_devices` | `False` |
| `albumLabel` | `lightbox2_album_label` | `"Image %1 of %2"` |
| `disableScrolling` | `lightbox2_disable_scrolling`| `False` |
| `fadeDuration` | `lightbox2_fade_duration`| `600` |
| `fitImagesInViewport` | `lightbox2_fit_images_in_viewport`| `True` |
| `imageFadeDuration` | `lightbox2_image_fade_duration`| `600` |
| `maxWidth` | `lightbox2_max_width`| `None` |
| `maxHeight` | `lightbox2_max_height`| `None` |
| `positionFromTop` | `lightbox2_position_from_top`| `50` |
| `resizeDuration` | `lightbox2_resize_duration`| `700` |
| `showImageNumberLabel` | `lightbox2_show_image_number_label`| `True` |
| `wrapAround` | `lightbox2_wrap_around`| `True` |
6 changes: 6 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@
# https://myst-parser.readthedocs.io/en/latest/configuration.html

myst_enable_extensions = ["colon_fence"]

# -- Options for sphinxcontrib.lightbox2 -------------------------------------

# The time it takes for the Lightbox container and overlay to fade in and out, in milliseconds
lightbox2_fade_duration = 100
lightbox2_image_fade_duration = 100
61 changes: 61 additions & 0 deletions sphinxcontrib/lightbox2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import dataclasses
import importlib.metadata
import json
import pathlib
import posixpath
import urllib.parse
from typing import Generic, TypeVar

from docutils import nodes
from sphinx.application import Sphinx
from sphinx.config import Config
from sphinx.environment import BuildEnvironment
from sphinx.util import display, osutil
from sphinx.util.typing import ExtensionMetadata
Expand All @@ -26,6 +30,7 @@
# No metadata is available, this could be because the tool is running from source
__version__ = "unknown"

T = TypeVar("T")
STATIC_FILES = (
pathlib.Path("assets/images/close.png"),
pathlib.Path("assets/images/next.png"),
Expand All @@ -37,6 +42,53 @@
)


@dataclasses.dataclass
class Lightbox2ConfigOption(Generic[T]):
name: str
default: T

def sphinx_config_name(self) -> str:
return "lightbox2_" + self.name

def js_config_name(self) -> str:
return snake_to_camel(self.name)


CONFIG_OPTIONS = (
Lightbox2ConfigOption("always_show_nav_on_touch_devices", False),
Lightbox2ConfigOption("album_label", "Image %1 of %2"),
Lightbox2ConfigOption("disable_scrolling", False),
Lightbox2ConfigOption("fade_duration", 600),
Lightbox2ConfigOption("fit_images_in_viewport", True),
Lightbox2ConfigOption("image_fade_duration", 600),
Lightbox2ConfigOption("max_width", None),
Lightbox2ConfigOption("max_height", None),
Lightbox2ConfigOption("position_from_top", 50),
Lightbox2ConfigOption("resize_duration", 700),
Lightbox2ConfigOption("show_image_number_label", True),
Lightbox2ConfigOption("wrap_around", True),
)


def snake_to_camel(snake_str: str) -> str:
"""Translate a snake_case string to camelCase"""
components = snake_str.split("_")
# Capitalize the first letter of each component except the first one
return components[0] + "".join(x.title() for x in components[1:])


def render_lightbox2_option_method_call(config: Config) -> str:
"""Render the lightbox.options method call with the configured options to a string"""
lightbox_options = {}

for option in CONFIG_OPTIONS:
val = getattr(config, option.sphinx_config_name(), None)
if val is None:
continue
lightbox_options[option.js_config_name()] = val
return f"lightbox.option({json.dumps(lightbox_options)})"


def start_lightbox_anchor(self: HTML5Translator, uri: str) -> None:
"""
Write the start of a lightbox anchor to the body
Expand Down Expand Up @@ -69,6 +121,10 @@ def install_static_files(app: Sphinx, env: BuildEnvironment) -> None:
elif dest_file_path.suffix == ".css":
app.add_css_file(str(dest_file_path.relative_to(static_dir)))

lightbox_options_path = dest_path / "js" / "lightbox2-options.js"
lightbox_options_path.write_text(render_lightbox2_option_method_call(env.config))
app.add_js_file(str(lightbox_options_path.relative_to(static_dir)))


def html_visit_plantuml(self: HTML5Translator, node: nodes.Element) -> None:

Expand Down Expand Up @@ -109,6 +165,11 @@ def html_depart_image(self: HTML5Translator, node: nodes.Element) -> None:
def setup(app: Sphinx) -> ExtensionMetadata:
app.require_sphinx("7.0")

for option in CONFIG_OPTIONS:
app.add_config_value(
option.sphinx_config_name(), default=option.default, rebuild="env", types=type(option.default)
)

if __PLANTUML_AVAILABLE__:
# sphinxcontrib.plantuml is available, override require the extension to be setup before we continue
app.setup_extension("sphinxcontrib.plantuml")
Expand Down

0 comments on commit 3b66845

Please sign in to comment.