Skip to content

Commit

Permalink
Migrate Gallery to Catalog
Browse files Browse the repository at this point in the history
Co-authored-by: Oleh Prypin <[email protected]>
  • Loading branch information
pawamoy and oprypin committed Dec 2, 2023
1 parent 7f75c2d commit ec6c880
Show file tree
Hide file tree
Showing 12 changed files with 527 additions and 0 deletions.
61 changes: 61 additions & 0 deletions .github/workflows/gallery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Gallery

on:
push:
pull_request:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- uses: actions/cache@v3
name: Cache/restore pip data
with:
path: ~/.cache/pip
key: pip

- name: Install Python dependencies
run: pip install -r requirements.txt

- name: Cache/restore Playwright browsers
uses: actions/cache@v3
with:
path: ~/.cache/ms-playwright/
key: playwright

- name: Install Playwright dependencies
run: shot-scraper install

- name: Build everything
run: python build_gallery.py

- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: gallery

deploy:
if: github.event_name == 'push' && github.ref_name == github.event.repository.default_branch
needs: build
concurrency:
group: "pages"
permissions:
pages: write
id-token: write
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Specific to this project
/logs/
/themes/
/gallery/
/docs/
/mkdocs.yml

# IntelliJ
target/
.idea/
Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.PHONY: build-gallery
build-gallery:
python -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/playwright install
.venv/bin/python build_gallery.py

.PHONY: serve-gallery
serve-gallery:
cd gallery; python -m http.server
209 changes: 209 additions & 0 deletions build_gallery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import argparse
import os
import shutil
import subprocess
import sys
import venv
from dataclasses import dataclass
from multiprocessing import Pool
from pathlib import Path

import mkdocs_get_deps
import yaml
from jinja2 import Environment
from shot_scraper.cli import cli as shot_scraper
from tqdm import tqdm


@dataclass
class Theme:
name: str
mkdocs_id: str
url: str = ""
pypi_id: str = ""
builtin: bool = False


_builtin_themes = [
Theme(name="MkDocs", mkdocs_id="mkdocs", builtin=True),
Theme(name="ReadTheDocs", mkdocs_id="readthedocs", builtin=True),
]


# Fetch themes from MkDocs catalog.
def get_themes() -> list[Theme]:
with open("projects.yaml") as file:
catalog = yaml.safe_load(file)
projects = catalog["projects"]
theming_category = [project for project in projects if project["category"] == "theming"]
themes = []
for project in theming_category:
if mkdocs_theme := project.get("mkdocs_theme"):
if "github_id" in project:
url = f"https://github.com/{project['github_id']}"
elif "gitlab_id" in project:
url = f"https://gitlab.com/{project['gitlab_id']}"
else:
url = ""
pypi_id = project.get("pypi_id", f"git+{url}")
if isinstance(mkdocs_theme, str):
themes.append(Theme(name=project["name"], url=url, pypi_id=pypi_id, mkdocs_id=mkdocs_theme))
else:
for theme in mkdocs_theme:
themes.append(
Theme(name=f"{project['name']} - {theme.title()}", url=url, pypi_id=pypi_id, mkdocs_id=theme)
)
return _builtin_themes + sorted(themes, key=lambda theme: theme.name.lower())


# Copy files and expand Jinja templates.
def _prepare_site(src_dir: Path, dest_dir: Path, themes: list[Theme], theme: Theme | None = None) -> None:
jinja = Environment(autoescape=False)
dest_dir.mkdir(parents=True, exist_ok=True)

for src_path in src_dir.rglob("*"):
if not src_path.is_file():
continue
dest_path = dest_dir.joinpath(src_path.relative_to(src_dir))
dest_path.parent.mkdir(parents=True, exist_ok=True)
if src_path.suffix in (".md", ".yml"):
content = src_path.read_text()
content = jinja.from_string(content).render(themes=themes, theme=theme)
dest_path.write_text(content)
else:
shutil.copyfile(src_path, dest_path)


# Prepare each theme (docs directory and configuration file).
def prepare_themes(themes: list[Theme]) -> None:
specimen_dir = Path("templates", "specimen")
for theme in themes:
# Copy specific directory, or default to specimen.
theme_dir = Path("themes", theme.mkdocs_id)
theme_conf_dir = Path("templates", "themes", theme.mkdocs_id)
if not theme_conf_dir.exists():
theme_conf_dir = specimen_dir
shutil.copytree(theme_conf_dir, theme_dir, dirs_exist_ok=True)

_prepare_site(specimen_dir, theme_dir, themes, theme=theme)


# Prepare the main documentation site.
def prepare_main(themes: list[Theme]) -> None:
_prepare_site(Path("templates", "main"), Path("."), themes)


# Create virtualenvs and install dependencies.
def install_deps(theme: Theme) -> None:
theme_dir = Path("themes", theme.mkdocs_id)
venv_dir = theme_dir / ".venv"
if not venv_dir.exists():
venv.create(venv_dir, with_pip=True)
deps = mkdocs_get_deps.get_deps(config_file=theme_dir / "mkdocs.yml")
subprocess.run(
[venv_dir / "bin" / "pip", "install", *deps],
check=False,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)


# Build theme sites.
def build_themes(themes: list[Theme]) -> None:
parser = argparse.ArgumentParser(prog="build_gallery.py")
parser.add_argument(
"-D",
"--no-deps",
dest="install_deps",
action="store_false",
default=True,
help="Don't install Python dependencies.",
)
parser.add_argument(
"-T",
"--no-themes",
dest="build_themes",
action="store_false",
default=True,
help="Don't rebuild each theme site.",
)
parser.add_argument(
"-S",
"--no-shots",
dest="take_screenshots",
action="store_false",
default=True,
help="Don't take screenshots of each theme.",
)

opts = parser.parse_args()

if not opts.install_deps:
print("Skipping dependencies installation")
else:
print("Preparing environments")

with Pool(len(os.sched_getaffinity(0))) as pool:
tuple(tqdm(pool.imap(install_deps, themes), total=len(themes)))

if not opts.build_themes:
print("Skipping themes building")
else:
logs_dir = Path("logs")
logs_dir.mkdir(exist_ok=True)
shutil.rmtree(Path("gallery", "themes"), ignore_errors=True)
Path("gallery", "themes").mkdir(parents=True)

def _build_theme(theme: Theme) -> None:
theme_dir = Path("themes", theme.mkdocs_id).absolute()
dest_dir = Path("gallery", "themes", theme.mkdocs_id).absolute()
print(f"Building {theme.name}")
with logs_dir.joinpath(f"{theme.mkdocs_id}.txt").open("w") as logs_file:
try:
subprocess.run(
[theme_dir.joinpath(".venv", "bin", "mkdocs"), "build", "-d", dest_dir],
stdout=logs_file,
stderr=logs_file,
check=True,
text=True,
cwd=theme_dir,
)
except subprocess.CalledProcessError:
print("FAILED!")

for theme in themes:
_build_theme(theme)

if not opts.take_screenshots:
print("Skipping screenshots")
else:
print("Taking screenshots")
Path("docs", "assets", "img").mkdir(parents=True, exist_ok=True)
for theme in tqdm(themes):
try:
shot_scraper(
[f"gallery/themes/{theme.mkdocs_id}/index.html", "-o", f"docs/assets/img/{theme.mkdocs_id}.png"]
)
except SystemExit:
pass
except Exception as error:
print(error)


# Build main documentation site.
def build_main() -> None:
print("Building gallery's main site")
subprocess.run([sys.executable, "-mmkdocs", "build", "--dirty"], check=True)


# Run everything.
def main() -> None:
themes = get_themes()
prepare_themes(themes)
prepare_main(themes)
build_themes(themes)
build_main()


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
black
jinja2
mkdocs-get-deps
mkdocs-material
pyyaml
shot-scraper
tqdm
Binary file added templates/main/docs/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions templates/main/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
hide:
- navigation
---

# Welcome to our gallery of MkDocs themes!

<style>
article img {
-webkit-filter: drop-shadow(0px 16px 10px rgba(100,100,100,0.6));
-moz-filter: drop-shadow(0px 16px 10px rgba(100,100,100,0.6));
-ms-filter: drop-shadow(0px 16px 10px rgba(100,100,100,0.6));
-o-filter: drop-shadow(0px 16px 10px rgba(100,100,100,0.6));
filter: drop-shadow(0px 16px 10px rgba(100,100,100,0.6));
}
</style>

{% for builtin in [true, false] %}
{% if builtin %}## Built-in themes{% else %}## Third-party themes{% endif %}

{% for theme in themes if theme.builtin == builtin %}
### {{theme.name}}

[![{{theme.name}}](assets/img/{{theme.mkdocs_id}}.png)](themes/{{theme.mkdocs_id}}){ title="Click to browse!" }

---
{% endfor %}
{% endfor %}
25 changes: 25 additions & 0 deletions templates/main/mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
site_name: Gallery
site_url: https://mkdocs.github.io/catalog
site_dir: gallery

theme:
name: material
logo: assets/logo.png
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: blue
toggle:
icon: material/brightness-7
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: blue
toggle:
icon: material/brightness-4
name: Switch to light mode

markdown_extensions:
- attr_list
- toc:
permalink: true
20 changes: 20 additions & 0 deletions templates/specimen/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Welcome to {{ theme.name }}

This page is built with the {% if theme.url %}[{{ theme.name }}]({{ theme.url }}){% else %}{{ theme.name }}{% endif %} theme,
and demonstrates how a few Markdown extensions and MkDocs plugins
will look within this theme.

{% if theme.pypi_id %}
To install the theme:

```bash
pip install {{ theme.pypi_id }}
```
{% endif %}

To build your docs with this theme:

```yaml
# mkdocs.yml
theme: {{ theme.mkdocs_id }}
```
1 change: 1 addition & 0 deletions templates/specimen/docs/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: calculator
Loading

0 comments on commit ec6c880

Please sign in to comment.